[529226] Integrate latest EMF inverse xref optimization
This backports in all custom Sirius cross-reference adapters the
latest version of the algorithmic improvement made in EMF in the
context of bug #471106.
See
http://git.eclipse.org/c/emf/org.eclipse.emf.git/commit/?id=0448d995991f08fd5764f1efe134f3a5395593cc
Bug: 529226
Change-Id: I240e12c9381d1ef06ff9d1ef2f3207718ba29729
Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
diff --git a/plugins/org.eclipse.sirius.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.common/META-INF/MANIFEST.MF
index e5f3fff..927536a 100644
--- a/plugins/org.eclipse.sirius.common/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.sirius.common/META-INF/MANIFEST.MF
@@ -19,11 +19,12 @@
org.eclipse.sirius.common.tools.api.query;version="2.0.4",
org.eclipse.sirius.common.tools.api.resource;version="2.1.0",
org.eclipse.sirius.common.tools.api.util;version="3.1.0",
- org.eclipse.sirius.common.tools.internal.assist;x-internal:=true;version="2.0.4",
- org.eclipse.sirius.common.tools.internal.ecore;x-internal:=true;version="2.0.4",
- org.eclipse.sirius.common.tools.internal.editing;x-internal:=true;version="2.0.4",
- org.eclipse.sirius.common.tools.internal.interpreter;x-internal:=true;version="3.1.0",
- org.eclipse.sirius.common.tools.internal.resource;x-internal:=true;version="2.0.4"
+ org.eclipse.sirius.common.tools.internal.assist;version="2.0.4";x-internal:=true,
+ org.eclipse.sirius.common.tools.internal.ecore;version="2.0.4";x-internal:=true,
+ org.eclipse.sirius.common.tools.internal.editing;version="2.0.4";x-internal:=true,
+ org.eclipse.sirius.common.tools.internal.interpreter;version="3.1.0";x-internal:=true,
+ org.eclipse.sirius.common.tools.internal.resource;version="2.0.4";x-internal:=true,
+ org.eclipse.sirius.common.tools.internal.util;version="5.1.1";x-internal:=true
Bundle-Activator: org.eclipse.sirius.common.tools.DslCommonPlugin$Implementation
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/ECrossReferenceAdapterWithUnproxyCapability.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/ECrossReferenceAdapterWithUnproxyCapability.java
index 4f00832..c29cc62 100644
--- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/ECrossReferenceAdapterWithUnproxyCapability.java
+++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/ECrossReferenceAdapterWithUnproxyCapability.java
@@ -15,7 +15,6 @@
import java.util.List;
import java.util.Map;
-import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -23,21 +22,21 @@
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.sirius.common.tools.internal.util.FastInverseCrossReferencesList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
- * {@link ECrossReferenceAdapter} that provides the capability to resolve all
- * proxy cross reference to a given resource.
+ * {@link ECrossReferenceAdapter} that provides the capability to resolve all proxy cross reference to a given resource.
*
* @noextend This class is not intended to be subclassed by clients.
* @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
*/
public class ECrossReferenceAdapterWithUnproxyCapability extends SiriusCrossReferenceAdapterImpl {
+
/**
- * InverseCrossReferencer to allow access to {@link #removeProxies(URI)} in
- * '@link InternalCrossReferencer}.
+ * InverseCrossReferencer to allow access to {@link #removeProxies(URI)} in '@link InternalCrossReferencer}.
*
* @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
*/
@@ -50,10 +49,9 @@
}
/**
- * Check if the proxyMap is null or not. Since change in
- * ECrossReferenceAdapter (bugzilla 400891), the proxyMap is no longer
- * used if the resolve() method returns true. In this case, we must
- * iterate on all crossReferences to retrieve corresponding proxies.
+ * Check if the proxyMap is null or not. Since change in ECrossReferenceAdapter (bugzilla 400891), the proxyMap
+ * is no longer used if the resolve() method returns true. In this case, we must iterate on all crossReferences
+ * to retrieve corresponding proxies.
*
* @return true if the proxy map is null.
*/
@@ -62,13 +60,11 @@
}
/**
- * Get all proxy {@link EObject EObjects} that have URI corresponding to
- * the <code>resourceURI</code>. Warning: this map is computed at each
- * call and can be costly.
+ * Get all proxy {@link EObject EObjects} that have URI corresponding to the <code>resourceURI</code>. Warning:
+ * this map is computed at each call and can be costly.
*
* @param resourceURI
- * The URI of the resource for which we want to get the proxy
- * EObjects.
+ * The URI of the resource for which we want to get the proxy EObjects.
* @return map of proxies with the URI as key.
*/
public Map<URI, List<EObject>> getProxiesOf(URI resourceURI) {
@@ -94,31 +90,7 @@
@Override
protected Collection<EStructuralFeature.Setting> newCollection() {
- return new BasicEList<EStructuralFeature.Setting>() {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected Object[] newData(int capacity) {
- return new EStructuralFeature.Setting[capacity];
- }
-
- @Override
- public boolean add(EStructuralFeature.Setting setting) {
- if (!isSettingTargets || ECrossReferenceAdapterWithUnproxyCapability.this.resolve()) {
- EObject eObject = setting.getEObject();
- EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
- EStructuralFeature.Setting[] settingData = (EStructuralFeature.Setting[]) data;
- for (int i = 0; i < size; ++i) {
- EStructuralFeature.Setting containedSetting = settingData[i];
- if (containedSetting.getEObject() == eObject && containedSetting.getEStructuralFeature() == eStructuralFeature) {
- return false;
- }
- }
- }
- addUnique(setting);
- return true;
- }
- };
+ return new FastInverseCrossReferencesList(() -> !ECrossReferenceAdapterWithUnproxyCapability.this.settingTargets || ECrossReferenceAdapterWithUnproxyCapability.this.resolve());
}
}
@@ -128,15 +100,13 @@
}
/**
- * Look at all EObjects of the specified resource and resolve proxy cross
- * reference that reference these EObjects.<BR>
- * A part of {@link #resolveAll(EObject)} has been duplicated to avoid the
- * time consumption of accessing to resourceURI for each objects of the same
- * resource.
+ * Look at all EObjects of the specified resource and resolve proxy cross reference that reference these
+ * EObjects.<BR>
+ * A part of {@link #resolveAll(EObject)} has been duplicated to avoid the time consumption of accessing to
+ * resourceURI for each objects of the same resource.
*
* @param resource
- * Each cross reference pointing to a proxy of this
- * <code>resource</code> will be resolved.
+ * Each cross reference pointing to a proxy of this <code>resource</code> will be resolved.
*/
public void resolveProxyCrossReferences(Resource resource) {
if (resource != null) {
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/SiriusCrossReferenceAdapterImpl.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/SiriusCrossReferenceAdapterImpl.java
index 46f67e0..ecff1a8 100644
--- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/SiriusCrossReferenceAdapterImpl.java
+++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/SiriusCrossReferenceAdapterImpl.java
@@ -16,11 +16,10 @@
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
-import org.eclipse.emf.common.util.BasicEList;
-import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.sirius.common.tools.internal.util.FastInverseCrossReferencesList;
/**
* Specific {@link ECrossReferenceAdapter} which resolve proxy ability can be disabled. All
@@ -74,33 +73,8 @@
return new InverseCrossReferencer() {
private static final long serialVersionUID = 1L;
- @Override
protected Collection<EStructuralFeature.Setting> newCollection() {
- return new BasicEList<EStructuralFeature.Setting>() {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected Object[] newData(int capacity) {
- return new EStructuralFeature.Setting[capacity];
- }
-
- @Override
- public boolean add(EStructuralFeature.Setting setting) {
- if (!isSettingTargets || SiriusCrossReferenceAdapterImpl.this.resolve()) {
- EObject eObject = setting.getEObject();
- EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
- EStructuralFeature.Setting[] settingData = (EStructuralFeature.Setting[]) data;
- for (int i = 0; i < size; ++i) {
- EStructuralFeature.Setting containedSetting = settingData[i];
- if (containedSetting.getEObject() == eObject && containedSetting.getEStructuralFeature() == eStructuralFeature) {
- return false;
- }
- }
- }
- addUnique(setting);
- return true;
- }
- };
+ return new FastInverseCrossReferencesList(() -> !SiriusCrossReferenceAdapterImpl.this.settingTargets || SiriusCrossReferenceAdapterImpl.this.resolve());
}
};
}
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/util/FastInverseCrossReferencesList.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/util/FastInverseCrossReferencesList.java
new file mode 100644
index 0000000..487f5dc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/util/FastInverseCrossReferencesList.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2005-2017 IBM Corporation, CEA, 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:
+ * IBM - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 433027
+ * Obeo - extracted internal BasicEList subclass
+ *******************************************************************************/
+package org.eclipse.sirius.common.tools.internal.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BooleanSupplier;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+// CHECKSTYLE:OFF
+/**
+ * A {@link BasicEList} optimized for use in inverse cross-referencers. It switches from a plain list to a map for
+ * storing inverse references when the number of settings increases beyond a threshold. Using a map allows for very fast
+ * containment testing, which can bring spectacular performance improvements when cross-referencing models where some
+ * elements are referenced a lot.
+ * <p>
+ * Extracted from org.eclipse.emf.ecore.util.ECrossReferenceAdapter.InverseCrossReferencer.newCollection() added in EMF
+ * 2.13 by http://git.eclipse.org/c/emf/org.eclipse.emf.git/commit/?id=0448d995991f08fd5764f1efe134f3a5395593cc.
+ */
+public final class FastInverseCrossReferencesList extends BasicEList<EStructuralFeature.Setting> {
+ private static final long serialVersionUID = 1L;
+
+ private static final int THRESHOLD = 100;
+
+ private Map<EObject, Object> map;
+
+ private BooleanSupplier checkUnique;
+
+ public FastInverseCrossReferencesList(BooleanSupplier checkUnique) {
+ this.checkUnique = checkUnique;
+ }
+
+ @Override
+ protected Object[] newData(int capacity) {
+ return new EStructuralFeature.Setting[capacity];
+ }
+
+ @Override
+ protected void didAdd(int index, EStructuralFeature.Setting setting) {
+ if (map != null) {
+ EObject eObject = setting.getEObject();
+ EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
+ Object object = map.get(eObject);
+ if (object == null) {
+ map.put(eObject, eStructuralFeature);
+ } else if (object instanceof Object[]) {
+ Object[] oldFeatures = (Object[]) object;
+ Object[] newFeatures = new Object[oldFeatures.length + 1];
+ System.arraycopy(oldFeatures, 0, newFeatures, 0, oldFeatures.length);
+ newFeatures[oldFeatures.length] = eStructuralFeature;
+ map.put(eObject, newFeatures);
+ } else {
+ Object[] newFeatures = new Object[2];
+ newFeatures[0] = object;
+ newFeatures[1] = eStructuralFeature;
+ map.put(eObject, newFeatures);
+ }
+ }
+ }
+
+ @Override
+ protected void didRemove(int index, EStructuralFeature.Setting setting) {
+ if (map != null) {
+ if (size < THRESHOLD / 2) {
+ map = null;
+ } else {
+ EObject eObject = setting.getEObject();
+ Object object = map.get(eObject);
+ if (object instanceof Object[]) {
+ Object[] oldFeatures = (Object[]) object;
+ EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
+ if (oldFeatures.length == 2) {
+ map.put(eObject, oldFeatures[0] == eStructuralFeature ? oldFeatures[1] : oldFeatures[0]);
+ } else {
+ Object[] newFeatures = new Object[oldFeatures.length - 1];
+ for (int i = 0; i < oldFeatures.length; ++i) {
+ Object oldFeature = oldFeatures[i];
+ if (oldFeature == eStructuralFeature) {
+ System.arraycopy(oldFeatures, i + 1, newFeatures, i, oldFeatures.length - i - 1);
+ break;
+ } else {
+ newFeatures[i] = oldFeatures[i];
+ }
+ }
+ map.put(eObject, newFeatures);
+ }
+ } else {
+ map.remove(eObject);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean add(EStructuralFeature.Setting setting) {
+ if (size > 0 && checkUnique.getAsBoolean()) {
+ EObject eObject = setting.getEObject();
+ if (size > THRESHOLD) {
+ if (map == null) {
+ map = new HashMap<EObject, Object>();
+ EStructuralFeature.Setting[] settingData = (EStructuralFeature.Setting[]) data;
+ for (int i = 0; i < size; ++i) {
+ didAdd(i, settingData[i]);
+ }
+ }
+
+ Object object = map.get(eObject);
+ if (object != null) {
+ EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
+ if (object == eStructuralFeature) {
+ return false;
+ } else if (object instanceof Object[]) {
+ Object[] features = (Object[]) object;
+ for (int i = 0; i < features.length; ++i) {
+ if (features[i] == eStructuralFeature) {
+ return false;
+ }
+ }
+ }
+ }
+ } else {
+ EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
+ EStructuralFeature.Setting[] settingData = (EStructuralFeature.Setting[]) data;
+ for (int i = 0; i < size; ++i) {
+ EStructuralFeature.Setting containedSetting = settingData[i];
+ if (containedSetting.getEObject() == eObject && containedSetting.getEStructuralFeature() == eStructuralFeature) {
+ return false;
+ }
+ }
+ }
+ }
+ addUnique(setting);
+ return true;
+ }
+}
+// CHECKSTYLE:ON
diff --git a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/perf/common/Session1MillionTests.java b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/perf/common/Session1MillionTests.java
index 48ba244..319f58c 100644
--- a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/perf/common/Session1MillionTests.java
+++ b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/perf/common/Session1MillionTests.java
@@ -44,9 +44,9 @@
/**
* limit is set empirically.
*/
- private static final long MAX_TIME_TO_OPEN_SECONDS = 110;
+ private static final long MAX_TIME_TO_OPEN_SECONDS = 15;
- private static final long MAX_TIME_TO_CLOSE_SECONDS = 10;
+ private static final long MAX_TIME_TO_CLOSE_SECONDS = 5;
private static final int NUMBER_Of_ELEMENTS = 966220;
diff --git a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/LocalResourceCollector.java b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/LocalResourceCollector.java
index c938de2..5445b87 100644
--- a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/LocalResourceCollector.java
+++ b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/LocalResourceCollector.java
@@ -17,7 +17,6 @@
import java.util.Map;
import java.util.WeakHashMap;
-import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -28,6 +27,7 @@
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.sirius.business.api.query.ResourceQuery;
import org.eclipse.sirius.common.tools.api.util.SiriusCrossReferenceAdapterImpl;
+import org.eclipse.sirius.common.tools.internal.util.FastInverseCrossReferencesList;
/**
* A {@link IResourceCollector} for local {@link Resource}.
@@ -231,33 +231,8 @@
@Override
protected Collection<EStructuralFeature.Setting> newCollection() {
- return new BasicEList<EStructuralFeature.Setting>() {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected Object[] newData(int capacity) {
- return new EStructuralFeature.Setting[capacity];
- }
-
- @Override
- public boolean add(EStructuralFeature.Setting setting) {
- if (!isSettingTargets || LocalResourceCollector.this.resolve()) {
- EObject eObject = setting.getEObject();
- EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
- EStructuralFeature.Setting[] settingData = (EStructuralFeature.Setting[]) data;
- for (int i = 0; i < size; ++i) {
- EStructuralFeature.Setting containedSetting = settingData[i];
- if (containedSetting.getEObject() == eObject && containedSetting.getEStructuralFeature() == eStructuralFeature) {
- return false;
- }
- }
- }
- addUnique(setting);
- return true;
- }
- };
+ return new FastInverseCrossReferencesList(() -> !LocalResourceCollector.this.settingTargets || LocalResourceCollector.this.resolve());
}
-
}
}