diff options
author | Esteban Dugueperoux | 2014-07-10 11:37:29 +0000 |
---|---|---|
committer | Esteban DUGUEPEROUX | 2014-12-22 11:50:22 +0000 |
commit | acd14288558beb396785c1464f67b6d431f5442c (patch) | |
tree | 2ad75b98bb317d335b37fc94f3d892485fc71ea2 | |
parent | 9f4ef75f80b9ccbdce23015547fd6c8b7e4a8235 (diff) | |
download | cdo-acd14288558beb396785c1464f67b6d431f5442c.tar.gz cdo-acd14288558beb396785c1464f67b6d431f5442c.tar.xz cdo-acd14288558beb396785c1464f67b6d431f5442c.zip |
[439337] Have CDOLockState prefetch to improve loading time
- Have CDOLockState prefetch to improve loading time when an
EContentAdapter exists on the ResourceSet.
- Bugzilla_439337_Test added to the suite to test CDOLockState prefetch.
- CDOView.options().isLockStatePrefetchEnabled()/setLockStatePrefetchEnabled()
new option
has been added to the API to allow CDOLockStates prefetch.
- org.eclipse.emf.cdo.common.revision.CDORevisionsLoadedEvent has been
added in API to be notified of new CDORevision loaded from
RevisionLoader.
- The difficulty is to have CDOViewImpl.objects cache filled before
updating the CDOViewImpl.lockStates cache.
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=439337
Change-Id: I061d91b30f732f8d67eaeb6215b4039e36d73f2d
Signed-off-by: Esteban Dugueperoux <esteban.dugueperoux@obeo.fr>
10 files changed, 614 insertions, 36 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF index f43900e3b2..3c0340ef51 100644 --- a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.common -Bundle-Version: 4.3.100.qualifier +Bundle-Version: 4.4.0.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -14,21 +14,21 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)";visibili org.eclipse.emf.ecore.change;bundle-version="[2.5.0,3.0.0)";visibility:=reexport, org.eclipse.emf.ecore.xmi;bundle-version="[2.5.0,3.0.0)";visibility:=reexport, org.eclipse.net4j.util;bundle-version="[3.0.0,4.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", - org.eclipse.emf.cdo.common.admin;version="4.3.100", - org.eclipse.emf.cdo.common.branch;version="4.3.100", - org.eclipse.emf.cdo.common.commit;version="4.3.100", - org.eclipse.emf.cdo.common.commit.handler;version="4.3.100", - org.eclipse.emf.cdo.common.id;version="4.3.100", - org.eclipse.emf.cdo.common.lob;version="4.3.100", - org.eclipse.emf.cdo.common.lock;version="4.3.100", - org.eclipse.emf.cdo.common.model;version="4.3.100", - org.eclipse.emf.cdo.common.protocol;version="4.3.100", - org.eclipse.emf.cdo.common.revision;version="4.3.100", - org.eclipse.emf.cdo.common.revision.delta;version="4.3.100", - org.eclipse.emf.cdo.common.security;version="4.3.100", - org.eclipse.emf.cdo.common.util;version="4.3.100", - org.eclipse.emf.cdo.internal.common;version="4.3.100"; +Export-Package: org.eclipse.emf.cdo.common;version="4.4.0", + org.eclipse.emf.cdo.common.admin;version="4.4.0", + org.eclipse.emf.cdo.common.branch;version="4.4.0", + org.eclipse.emf.cdo.common.commit;version="4.4.0", + org.eclipse.emf.cdo.common.commit.handler;version="4.4.0", + org.eclipse.emf.cdo.common.id;version="4.4.0", + org.eclipse.emf.cdo.common.lob;version="4.4.0", + org.eclipse.emf.cdo.common.lock;version="4.4.0", + org.eclipse.emf.cdo.common.model;version="4.4.0", + org.eclipse.emf.cdo.common.protocol;version="4.4.0", + org.eclipse.emf.cdo.common.revision;version="4.4.0", + org.eclipse.emf.cdo.common.revision.delta;version="4.4.0", + org.eclipse.emf.cdo.common.security;version="4.4.0", + org.eclipse.emf.cdo.common.util;version="4.4.0", + org.eclipse.emf.cdo.internal.common;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -38,11 +38,11 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.ui, org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.server.hibernate", - org.eclipse.emf.cdo.internal.common.branch;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.branch;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.server.hibernate", - org.eclipse.emf.cdo.internal.common.bundle;version="4.3.100";x-internal:=true, - org.eclipse.emf.cdo.internal.common.commit;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.bundle;version="4.4.0";x-internal:=true, + org.eclipse.emf.cdo.internal.common.commit;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -51,7 +51,7 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.ui, org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.common.id;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.id;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -62,9 +62,9 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.admin, org.eclipse.emf.cdo.server.admin", - org.eclipse.emf.cdo.internal.common.lock;version="4.3.100";x-internal:=true, - org.eclipse.emf.cdo.internal.common.messages;version="4.3.100";x-internal:=true, - org.eclipse.emf.cdo.internal.common.model;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.lock;version="4.4.0";x-internal:=true, + org.eclipse.emf.cdo.internal.common.messages;version="4.4.0";x-internal:=true, + org.eclipse.emf.cdo.internal.common.model;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -73,7 +73,7 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.ui, org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.common.revision;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.revision;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -82,7 +82,7 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.ui, org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.common.revision.delta;version="4.3.100"; + org.eclipse.emf.cdo.internal.common.revision.delta;version="4.4.0"; x-friends:="org.eclipse.emf.cdo.common, org.eclipse.emf.cdo.common.db, org.eclipse.emf.cdo, @@ -91,12 +91,12 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.3.100", org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.ui, org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.spi.common;version="4.3.100", - org.eclipse.emf.cdo.spi.common.admin;version="4.3.100", - org.eclipse.emf.cdo.spi.common.branch;version="4.3.100", - org.eclipse.emf.cdo.spi.common.commit;version="4.3.100", - org.eclipse.emf.cdo.spi.common.id;version="4.3.100", - org.eclipse.emf.cdo.spi.common.lock;version="4.3.100", - org.eclipse.emf.cdo.spi.common.model;version="4.3.100", - org.eclipse.emf.cdo.spi.common.protocol;version="4.3.100", - org.eclipse.emf.cdo.spi.common.revision;version="4.3.100" + org.eclipse.emf.cdo.spi.common;version="4.4.0", + org.eclipse.emf.cdo.spi.common.admin;version="4.4.0", + org.eclipse.emf.cdo.spi.common.branch;version="4.4.0", + org.eclipse.emf.cdo.spi.common.commit;version="4.4.0", + org.eclipse.emf.cdo.spi.common.id;version="4.4.0", + org.eclipse.emf.cdo.spi.common.lock;version="4.4.0", + org.eclipse.emf.cdo.spi.common.model;version="4.4.0", + org.eclipse.emf.cdo.spi.common.protocol;version="4.4.0", + org.eclipse.emf.cdo.spi.common.revision;version="4.4.0" diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionManager.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionManager.java index 6c8fe226ae..b87b81e235 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionManager.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionManager.java @@ -18,6 +18,8 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.net4j.util.event.INotifier; + import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; @@ -51,7 +53,7 @@ import java.util.List; * @apiviz.has {@link CDORevisionCache} * @apiviz.uses {@link CDORevision} - - loads */ -public interface CDORevisionManager +public interface CDORevisionManager extends INotifier { /** * Returns the {@link CDORevision#getEClass() type} of an object if a revision for that object is in the revision diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionsLoadedEvent.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionsLoadedEvent.java new file mode 100644 index 0000000000..a0a83b63e9 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionsLoadedEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2014 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: + * Esteban Dugueperoux - initial API and implementation + */ +package org.eclipse.emf.cdo.common.revision; + +import org.eclipse.net4j.util.event.IEvent; + +import java.util.List; + +/** + * An {@link IEvent event} fired from a {@link CDORevisionManager revision manager} when a new {@link CDORevision revision} has + * been loaded. + * + * @author Esteban Dugueperoux + * @since 4.4 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface CDORevisionsLoadedEvent extends IEvent +{ + public CDORevisionManager getSource(); + + public List<? extends CDORevision> getPrimaryLoadedRevisions(); + + public List<? extends CDORevision> getAdditionalLoadedRevisions(); +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java index f149dffc1d..92f794c588 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java @@ -21,7 +21,9 @@ import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionCache; import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.common.revision.CDORevisionManager; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.revision.CDORevisionsLoadedEvent; import org.eclipse.emf.cdo.internal.common.bundle.OM; import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision; @@ -33,6 +35,7 @@ import org.eclipse.emf.cdo.spi.common.revision.RevisionInfo; import org.eclipse.emf.cdo.spi.common.revision.SyntheticCDORevision; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; +import org.eclipse.net4j.util.event.Event; import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.trace.ContextTracer; @@ -290,7 +293,26 @@ public class CDORevisionManagerImpl extends Lifecycle implements InternalCDORevi List<RevisionInfo> infosToLoad = createRevisionInfos(ids, branchPoint, prefetchDepth, loadOnDemand, infos); if (infosToLoad != null) { - loadRevisions(infosToLoad, branchPoint, referenceChunk, prefetchDepth); + List<? extends CDORevision> additionalLoadedRevisions // + = loadRevisions(infosToLoad, branchPoint, referenceChunk, prefetchDepth); + List<? extends CDORevision> primaryLoadedRevisions // + = getResultsAndSynthetics(infosToLoad.toArray(new RevisionInfo[0]), null); + + if (primaryLoadedRevisions != null && !primaryLoadedRevisions.isEmpty() || additionalLoadedRevisions != null + && !additionalLoadedRevisions.isEmpty()) + { + if (primaryLoadedRevisions == null) + { + primaryLoadedRevisions = Collections.emptyList(); + } + + if (additionalLoadedRevisions == null) + { + additionalLoadedRevisions = Collections.emptyList(); + } + + fireEvent(new RevisionsLoadedEvent(this, primaryLoadedRevisions, additionalLoadedRevisions)); + } } return getResultsAndSynthetics(infos, synthetics); @@ -557,4 +579,41 @@ public class CDORevisionManagerImpl extends Lifecycle implements InternalCDORevi // Reached main branch return null; } + + /** + * @author Esteban Dugueperoux + */ + private static class RevisionsLoadedEvent extends Event implements CDORevisionsLoadedEvent + { + private static final long serialVersionUID = 1L; + + private List<? extends CDORevision> primaryLoadedRevisions; + + private List<? extends CDORevision> additionalLoadedRevisions; + + public RevisionsLoadedEvent(CDORevisionManager revisionManager, List<? extends CDORevision> primaryLoadedRevisions, + List<? extends CDORevision> additionalLoadedRevisions) + { + super(revisionManager); + this.primaryLoadedRevisions = primaryLoadedRevisions; + this.additionalLoadedRevisions = additionalLoadedRevisions; + } + + @Override + public CDORevisionManager getSource() + { + return (CDORevisionManager)super.getSource(); + } + + public List<? extends CDORevision> getPrimaryLoadedRevisions() + { + return primaryLoadedRevisions; + } + + public List<? extends CDORevision> getAdditionalLoadedRevisions() + { + return additionalLoadedRevisions; + } + } + } 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 76c298f4eb..c10911cb2d 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 @@ -48,6 +48,7 @@ import org.eclipse.emf.cdo.view.CDOAdapterPolicy; import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer; import org.eclipse.emf.cdo.view.CDOFetchRuleManager; import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; +import org.eclipse.emf.cdo.view.CDOLockStateLoadingPolicy; import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy; import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy; import org.eclipse.emf.cdo.view.CDOView; @@ -371,11 +372,30 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd return false; } + public boolean isLockStatePrefetchEnabled() + { + return false; + } + public void setLockNotificationEnabled(boolean enabled) { throw new UnsupportedOperationException(); } + public CDOLockStateLoadingPolicy getLockStateLoadingPolicy() + { + return null; + } + + public void setLockStateLoadingPolicy(CDOLockStateLoadingPolicy lockStateLoadingPolicy) + { + } + + public void setLockStatePrefetchEnabled(boolean enabled) + { + throw new UnsupportedOperationException(); + } + public CDOAdapterPolicy[] getChangeSubscriptionPolicies() { return ADAPTER_POLICIES; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_439337_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_439337_Test.java new file mode 100644 index 0000000000..9183a5dd69 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_439337_Test.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014 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: + * Esteban Dugueperoux - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.CDOObject; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.net4j.protocol.CDOClientProtocol; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; +import org.eclipse.emf.cdo.view.CDOView; + +import org.eclipse.emf.internal.cdo.session.DelegatingSessionProtocol; + +import org.eclipse.net4j.signal.Signal; +import org.eclipse.net4j.signal.SignalScheduledEvent; +import org.eclipse.net4j.util.event.IEvent; +import org.eclipse.net4j.util.event.IListener; + +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.util.EContentAdapter; +import org.eclipse.emf.spi.cdo.CDOSessionProtocol; +import org.eclipse.emf.spi.cdo.InternalCDOSession; + +import java.util.HashMap; +import java.util.Map; + +/** + * Bug 439337 about {@link CDOLockState lock state} prefetch following a {@link CDORevision revision} prefetch. + * + * @author Esteban Dugueperoux + */ +public class Bugzilla_439337_Test extends AbstractCDOTest +{ + private static final String RESOURCE_NAME = "test1.model1"; + + private static final int NB_CATEGORIES = 10; + + @Override + public void setUp() throws Exception + { + super.setUp(); + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + + CDOResource resource = transaction.getOrCreateResource(getResourcePath(RESOURCE_NAME)); + Company company = getModel1Factory().createCompany(); + for (int i = 0; i < NB_CATEGORIES; i++) + { + Category category = getModel1Factory().createCategory(); + category.setName("Category n°" + i); + company.getCategories().add(category); + } + resource.getContents().add(company); + transaction.commit(); + } + + /** + * Test {@link CDOLockState} API without prefetch. + */ + public void testCDOLockStateWithoutPrefetch() throws Exception + { + CDOSession session = openSession(); + CDOView view = session.openView(); + testCDOLockState(view, false); + } + + /** + * Test {@link CDOLockState} API with prefetch. + */ + public void testCDOLockStateWithPrefetch() throws Exception + { + CDOSession session = openSession(); + CDOView view = session.openView(); + view.options().setLockStatePrefetchEnabled(true); + testCDOLockState(view, true); + } + + private void testCDOLockState(CDOView view, boolean cdoLockStatePrefetchEnabled) + { + view.getResourceSet().eAdapters().add(new EContentAdapterQueringCDOLockState()); + NBRequestsCallsCounter nbRequestsCallsCounter = new NBRequestsCallsCounter(view); + view.getResource(getResourcePath(RESOURCE_NAME + "?" + CDOResource.PREFETCH_PARAMETER + "=" + Boolean.TRUE)); + + Map<Short, Integer> nbRequestsCalls = nbRequestsCallsCounter.getNBRequestsCalls(); + String assertMessage = "4 differents kinds of requests should have been sent, QueryRequest, QueryCancel, LoadRevisionsRequest and LockStateRequest"; + // QueryRequest, QueryCancel are used to get the resourcePath + assertEquals(assertMessage, 4, nbRequestsCalls.size()); + assertEquals(true, nbRequestsCalls.containsKey(CDOProtocolConstants.SIGNAL_QUERY)); + assertEquals(true, nbRequestsCalls.containsKey(CDOProtocolConstants.SIGNAL_QUERY_CANCEL)); + assertEquals(true, nbRequestsCalls.containsKey(CDOProtocolConstants.SIGNAL_LOAD_REVISIONS)); + assertEquals(true, nbRequestsCalls.containsKey(CDOProtocolConstants.SIGNAL_LOCK_STATE)); + assertEquals("1 single query request should have been sent to get the resourcePath", Integer.valueOf(1), + nbRequestsCalls.get(CDOProtocolConstants.SIGNAL_QUERY)); + assertEquals("1 single query request should have been sent to cancel the single QueryRequest", Integer.valueOf(1), + nbRequestsCalls.get(CDOProtocolConstants.SIGNAL_QUERY_CANCEL)); + assertEquals( + "3 load revisions request should have been sent, 2 first for CDORevisions of CDOResourceFolders to get resource path and another in prefetch to load all CDORevisions of CDOResource", + Integer.valueOf(3), nbRequestsCalls.get(CDOProtocolConstants.SIGNAL_LOAD_REVISIONS)); + Integer expectedNbLockStateRequestCalls = Integer.valueOf((cdoLockStatePrefetchEnabled ? 0 : NB_CATEGORIES) + 2); + assertEquals("As CDOLockState prefetch is " + (cdoLockStatePrefetchEnabled ? "" : "not ") + "enabled " + + expectedNbLockStateRequestCalls + " LockStateRequests should have been sent to the server", + expectedNbLockStateRequestCalls, nbRequestsCalls.get(CDOProtocolConstants.SIGNAL_LOCK_STATE)); + } + + /** + * {@link IListener} to count sent request and their number. + */ + private static class NBRequestsCallsCounter implements IListener + { + private Map<Short, Integer> nbRequestsCalls = new HashMap<Short, Integer>(); + + public NBRequestsCallsCounter(CDOView view) + { + + InternalCDOSession internalCDOSession = (InternalCDOSession)view.getSession(); + CDOSessionProtocol sessionProtocol = internalCDOSession.getSessionProtocol(); + CDOClientProtocol cdoClientProtocol = null; + if (sessionProtocol instanceof CDOClientProtocol) + { + cdoClientProtocol = (CDOClientProtocol)sessionProtocol; + } + else if (sessionProtocol instanceof DelegatingSessionProtocol) + { + DelegatingSessionProtocol delegatingSessionProtocol = (DelegatingSessionProtocol)sessionProtocol; + CDOSessionProtocol delegate = delegatingSessionProtocol.getDelegate(); + if (delegate instanceof CDOClientProtocol) + { + cdoClientProtocol = (CDOClientProtocol)delegate; + } + } + if (cdoClientProtocol != null) + { + cdoClientProtocol.addListener(this); + } + } + + public void notifyEvent(IEvent event) + { + if (event instanceof SignalScheduledEvent) + { + @SuppressWarnings("unchecked") + SignalScheduledEvent<Object> signalScheduledEvent = (SignalScheduledEvent<Object>)event; + Signal signal = signalScheduledEvent.getSignal(); + short signalID = signal.getID(); + Integer nbRequestCalls = nbRequestsCalls.get(signalID); + if (nbRequestCalls == null) + { + nbRequestCalls = 0; + } + nbRequestCalls++; + nbRequestsCalls.put(signalID, nbRequestCalls); + } + } + + public Map<Short, Integer> getNBRequestsCalls() + { + return nbRequestsCalls; + } + + } + + /** + * A {@link EContentAdapter} to request {@link CDOLockState} on each object of a {@link ResourceSet}. + */ + private static class EContentAdapterQueringCDOLockState extends EContentAdapter + { + + @Override + protected void addAdapter(Notifier notifier) + { + if (notifier instanceof EObject) + { + EObject eObject = (EObject)notifier; + CDOObject cdoObject = CDOUtil.getCDOObject(eObject); + if (cdoObject != null) + { + cdoObject.cdoLockState(); + } + } + + super.addAdapter(notifier); + + } + } + +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDODefaultLockStateLoadingPolicy.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDODefaultLockStateLoadingPolicy.java new file mode 100644 index 0000000000..eb6efc6f60 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDODefaultLockStateLoadingPolicy.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2004-2014 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.view; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.revision.CDORevision; + +/** + * The default {@link CDOLockStateLoadingPolicy lock state loading policy} which ask to load {@link CDOLockState lock state} for each loaded {@link CDORevision revision} with the same number of request to server as for revisions requests. + * + * @author Esteban Dugueperoux + * @since 4.4 + */ +public class CDODefaultLockStateLoadingPolicy implements CDOLockStateLoadingPolicy +{ + public boolean loadLockState(CDOID id) + { + return true; + } +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLockStateLoadingPolicy.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLockStateLoadingPolicy.java new file mode 100644 index 0000000000..7d95e7602f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLockStateLoadingPolicy.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004-2014 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: + * Esteban Dugueperoux - initial API and implementation + */ +package org.eclipse.emf.cdo.view; + +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.eresource.CDOResource; +import org.eclipse.emf.cdo.view.CDOView.Options; + +import org.eclipse.emf.ecore.resource.ResourceSet; + +/** + * An interface to control if {@link CDOLockState lock states} are loaded when {@link CDORevision revisions} are loaded to limit requests sent to server. This interface is to be used when {@link Options#setLockStatePrefetchEnabled(boolean) lock state prefetch view option} is enabled. + * <br/> + * <br/> + * Note that lock states will not be loaded automatically for {@link CDOResource} when being created through {@link ResourceSet#getResource(org.eclipse.emf.common.util.URI, boolean)}, {@link CDOResource#cdoLockState()} must be called explicitly to load it. + * @see Options#setLockStatePrefetchEnabled(boolean) + * @author Esteban Dugueperoux + * @since 4.4 + */ +public interface CDOLockStateLoadingPolicy +{ + /** + * Tell if the {@link CDOLockState lock state} must be loaded for the current {@link CDOView view} when the {@link CDORevision revision} corresponding to the specified {@link CDOID id} is loaded. + * + * @param id the of the loaded revision + * @return true to have lock state loaded for the specified revision's id for the current view + */ + boolean loadLockState(CDOID id); +} 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 ef8eb9eeb3..19311686e5 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 @@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.commit.CDOCommitHistory; 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.CDOBinaryResource; @@ -618,6 +619,34 @@ IContainer<CDOResourceNode> public void setInvalidationNotificationEnabled(boolean enabled); /** + * Indicates whether this view will fetch {@link CDOLockState lock states} in its cache when a {@link CDORevision revision} is fetched. A lock state is fetched only if the view's cache does not contains it already or {@link Options#isLockNotificationEnabled()} return false, as in this last case the view's lock state cache can be outdated. + * + * @see CDOLockState + * @since 4.4 + */ + public boolean isLockStatePrefetchEnabled(); + + /** + * Specifies whether this view will load {@link CDOLockState lock states} in its cache when a {@link CDORevision revision} is loaded. A lock state is loaded only if the view's cache does not contains it already or {@link Options#isLockNotificationEnabled() lock notification view option} is disabled, as in this last case the view's lock state cache can be outdated. + * + * Note that lock state will not be loaded automatically for CDOResource, {@link CDOResource#cdoLockState()} must be called explicitly to load it. + * + * @see CDOLockState + * @since 4.4 + */ + public void setLockStatePrefetchEnabled(boolean enabled); + + /** + * @since 4.4 + */ + public CDOLockStateLoadingPolicy getLockStateLoadingPolicy(); + + /** + * @since 4.4 + */ + public void setLockStateLoadingPolicy(CDOLockStateLoadingPolicy lockStateLoadingPolicy); + + /** * @since 3.0 */ public CDOInvalidationPolicy getInvalidationPolicy(); @@ -791,6 +820,19 @@ IContainer<CDOResourceNode> } /** + * An {@link IOptionsEvent options event} fired from common view {@link CDOCommonView#options() options} when the + * {@link Options#setLockStatePrefetchEnabled(boolean) lock state prefetch enabled} option has changed. + * + * @author Esteban Dugueperoux + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 4.4 + */ + public interface LockStatePrefetchEvent extends IOptionsEvent + { + } + + /** * An {@link IOptionsEvent options event} fired from view {@link CDOView#options() options} when the * {@link Options#setInvalidationNotificationEnabled(boolean) invalidation notification enabled} option has changed. * 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 385ae783e3..65279d0506 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 @@ -15,6 +15,7 @@ package org.eclipse.emf.internal.cdo.view; import org.eclipse.emf.cdo.CDONotification; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.CDOState; +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; @@ -29,6 +30,7 @@ import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.common.revision.CDORevisionManager; +import org.eclipse.emf.cdo.common.revision.CDORevisionsLoadedEvent; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.common.util.CDOCommonUtil; import org.eclipse.emf.cdo.common.util.CDOException; @@ -43,8 +45,10 @@ import org.eclipse.emf.cdo.util.LockTimeoutException; import org.eclipse.emf.cdo.util.ReadOnlyException; import org.eclipse.emf.cdo.util.StaleRevisionLockException; import org.eclipse.emf.cdo.view.CDOAdapterPolicy; +import org.eclipse.emf.cdo.view.CDODefaultLockStateLoadingPolicy; import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer; import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; +import org.eclipse.emf.cdo.view.CDOLockStateLoadingPolicy; import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy; import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy; import org.eclipse.emf.cdo.view.CDOView; @@ -1683,6 +1687,84 @@ public class CDOViewImpl extends AbstractCDOView } /** + * A {@link IListener} to prefetch {@link CDOLockState lockstates} when {@link CDORevision revisions} are loaded, according to {@link Options#setLockStatePrefetchEnabled(boolean)} option. + * + * @author Esteban Dugueperoux + */ + private final class LockStatePrefetcher implements IListener + { + public LockStatePrefetcher() + { + getSession().getRevisionManager().addListener(this); + } + + public void notifyEvent(IEvent event) + { + if (event instanceof CDORevisionsLoadedEvent) + { + CDORevisionsLoadedEvent revisionsLoadedEvent = (CDORevisionsLoadedEvent)event; + List<CDORevision> loadedRevisions = new ArrayList<CDORevision>(); + loadedRevisions.addAll(revisionsLoadedEvent.getPrimaryLoadedRevisions()); + loadedRevisions.addAll(revisionsLoadedEvent.getAdditionalLoadedRevisions()); + + Map<CDOID, CDOObject> ids = updateCDOViewObjectsCache(loadedRevisions); + if (!ids.isEmpty()) + { + updateCDOViewLockStatesCache(ids.keySet()); + } + } + } + + private Map<CDOID, CDOObject> updateCDOViewObjectsCache(List<CDORevision> loadedRevisions) + { + Map<CDOID, CDOObject> ids = new HashMap<CDOID, CDOObject>(); + CDOLockStateLoadingPolicy lockStateLoadingPolicy = options().getLockStateLoadingPolicy(); + for (CDORevision revision : loadedRevisions) + { + CDOID id = revision.getID(); + if (id != null && lockStateLoadingPolicy.loadLockState(id)) + { + // - Don't ask to create an object for CDOResource as the caller of ResourceSet.getResource() + // can have created it but not yet registered in CDOView. + // - Don't ask others CDOResourceNode either as it will create some load revisions request + // in addition to mode without lock state prefetch + boolean isResourceNode = revision.isResourceNode(); + InternalCDOObject object = getObject(id, !isResourceNode); + if (object != null) + { + ids.put(id, object); + } + } + } + + return ids; + } + + private void updateCDOViewLockStatesCache(Set<CDOID> ids) + { + CDOLockState[] alreadyLoadedLockStates = getLockStates(ids, false); + if (alreadyLoadedLockStates == null || alreadyLoadedLockStates.length < ids.size() + || !options().isLockNotificationEnabled()) + { + CDOLockState[] lockStates = getLockStates(ids); + updateLockStates(lockStates); + for (CDOCommonView view : getSession().getViews()) + { + if (view != CDOViewImpl.this && view.getBranch() == getBranch()) + { + updateLockStates(lockStates); + } + } + } + } + + public void dispose() + { + getSession().getRevisionManager().removeListener(this); + } + } + + /** * @author Eike Stepper */ private final class InvalidationRunnable implements Runnable @@ -1817,6 +1899,12 @@ public class CDOViewImpl extends AbstractCDOView private boolean lockNotificationsEnabled; + private boolean lockStatePrefetchEnabled; + + private CDOLockStateLoadingPolicy lockStateLoadingPolicy = new CDODefaultLockStateLoadingPolicy(); + + private LockStatePrefetcher lockStatePrefetcher; + private CDORevisionPrefetchingPolicy revisionPrefetchingPolicy = CDOUtil .createRevisionPrefetchingPolicy(NO_REVISION_PREFETCHING); @@ -1961,6 +2049,56 @@ public class CDOViewImpl extends AbstractCDOView fireEvent(event); } + public boolean isLockStatePrefetchEnabled() + { + return lockStatePrefetchEnabled; + } + + public void setLockStatePrefetchEnabled(boolean enabled) + { + checkActive(); + + IEvent event = null; + synchronized (CDOViewImpl.this) + { + if (enabled != lockStatePrefetchEnabled) + { + lockStatePrefetchEnabled = enabled; + if (enabled) + { + lockStatePrefetcher = new LockStatePrefetcher(); + } + else + { + lockStatePrefetcher.dispose(); + lockStatePrefetcher = null; + } + + event = new LockStatePrefetchEventImpl(); + } + } + + fireEvent(event); + } + + public CDOLockStateLoadingPolicy getLockStateLoadingPolicy() + { + synchronized (CDOViewImpl.this) + { + return lockStateLoadingPolicy; + } + } + + public void setLockStateLoadingPolicy(CDOLockStateLoadingPolicy lockStateLoadingPolicy) + { + checkActive(); + + synchronized (CDOViewImpl.this) + { + this.lockStateLoadingPolicy = lockStateLoadingPolicy; + } + } + public boolean hasChangeSubscriptionPolicies() { synchronized (CDOViewImpl.this) @@ -2295,6 +2433,19 @@ public class CDOViewImpl extends AbstractCDOView } /** + * @author Esteban Dugueperoux + */ + private final class LockStatePrefetchEventImpl extends OptionsEvent implements LockStatePrefetchEvent + { + private static final long serialVersionUID = 1L; + + public LockStatePrefetchEventImpl() + { + super(OptionsImpl.this); + } + } + + /** * @author Eike Stepper */ private final class RevisionPrefetchingPolicyEventImpl extends OptionsEvent implements |