PapyrusDiagramPostComparison performs poorly
It has a performance of O(n^3). It's better to set all getRequires() at
once, at avoid uniqueness testing for very large lists. It's also
important to turn off notification because each addAll otherwise also
has O(n^2) performance from merging all the inverse notifications.
Change-Id: Ifd24d5eb71dcd5c00cb40bfbb153fe1e4ec3525e
Signed-off-by: Philip Langer <planger@eclipsesource.com>
diff --git a/plugins/compare/bundles/org.eclipse.papyrus.compare.diagram/src/org/eclipse/papyrus/compare/diagram/internal/PapyrusDiagramPostComparison.java b/plugins/compare/bundles/org.eclipse.papyrus.compare.diagram/src/org/eclipse/papyrus/compare/diagram/internal/PapyrusDiagramPostComparison.java
index 0e92250..d54db11 100644
--- a/plugins/compare/bundles/org.eclipse.papyrus.compare.diagram/src/org/eclipse/papyrus/compare/diagram/internal/PapyrusDiagramPostComparison.java
+++ b/plugins/compare/bundles/org.eclipse.papyrus.compare.diagram/src/org/eclipse/papyrus/compare/diagram/internal/PapyrusDiagramPostComparison.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 2017 Obeo 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
@@ -7,14 +7,19 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - performance improvements
*******************************************************************************/
package org.eclipse.papyrus.compare.diagram.internal;
+import com.google.common.collect.LinkedHashMultimap;
+
+import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.merge.ResourceChangeAdapter;
import org.eclipse.emf.compare.merge.ResourceChangeAdapter.IResourceChangeParticipant;
import org.eclipse.emf.ecore.util.EcoreUtil;
@@ -90,12 +95,32 @@
for (Object key : indexer.getEquivalentDiffsKeySet()) {
Set<Diff> diffs = indexer.getEquivalentDiffs(key);
if (diffs.size() > 1) {
- for (Diff diff : diffs) {
- for (Diff other : diffs) {
- if (other != diff && other.getSource() == diff.getSource()) {
- diff.getRequires().add(other);
+ // Keep a map of equivalent diffs based on having the same source.
+ LinkedHashMultimap<DifferenceSource, Diff> sourceDiffs = LinkedHashMultimap.create();
+ try {
+ for (Diff diff : diffs) {
+ sourceDiffs.put(diff.getSource(), diff);
+ // Turn off notification delivery because we can end up populating very large
+ // relations; processing all those notifications is unnecessary at this point in time,
+ // because the reference involved is bi-directional, cross referencers don't need to
+ // monitor it.
+ diff.eSetDeliver(false);
+ }
+
+ for (DifferenceSource differenceSource : sourceDiffs.keySet()) {
+ Set<Diff> equivalentDiffs = sourceDiffs.get(differenceSource);
+ for (Diff diff : equivalentDiffs) {
+ List<Diff> requires = diff.getRequires();
+ requires.addAll(equivalentDiffs);
+ // Remove the circular requirement.
+ requires.remove(diff);
}
}
+ } finally {
+ for (Diff diff : diffs) {
+ // Turn notification delivery back on after updating the requires references.
+ diff.eSetDeliver(true);
+ }
}
}
}