aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Besedin2011-09-09 14:05:49 (EDT)
committerOleg Besedin2011-09-09 14:05:49 (EDT)
commitc56ff7b31d46a97e0ecca46da3de1c447ba5e059 (patch)
tree0f94eaceeb896ff543a743639791fdbed1786f42
parentf295d953913532ad08a9ff4853dd1c5a2129de73 (diff)
downloadeclipse.platform.runtime-c56ff7b31d46a97e0ecca46da3de1c447ba5e059.zip
eclipse.platform.runtime-c56ff7b31d46a97e0ecca46da3de1c447ba5e059.tar.gz
eclipse.platform.runtime-c56ff7b31d46a97e0ecca46da3de1c447ba5e059.tar.bz2
Bug 357268 - Eclipse contexts: reduce overhead of invalidations
-rw-r--r--bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/Computation.java84
-rw-r--r--bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextObjectSupplier.java17
-rw-r--r--bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java217
-rw-r--r--bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/TrackableComputationExt.java43
-rw-r--r--bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java104
5 files changed, 176 insertions, 289 deletions
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/Computation.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/Computation.java
index 703bff2..f88761b 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/Computation.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/Computation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * Copyright (c) 2009, 2011 IBM Corporation 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
@@ -10,91 +10,23 @@
*******************************************************************************/
package org.eclipse.e4.core.internal.contexts;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
import java.util.Set;
-import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.internal.contexts.EclipseContext.Scheduled;
abstract public class Computation {
- /**
- * Computations must define equals because they are stored in a set.
- */
- public abstract boolean equals(Object arg0);
+ protected boolean validComputation = true;
- /**
- * Computations must define hashCode because they are stored in a set.
- */
- public abstract int hashCode();
-
- protected Map<EclipseContext, Set<String>> dependencies = new HashMap<EclipseContext, Set<String>>();
-
- public void addDependency(EclipseContext context, String name) {
- Set<String> properties = dependencies.get(context);
- if (properties == null) {
- properties = new HashSet<String>(4);
- dependencies.put(context, properties);
- }
- properties.add(name);
- }
-
- protected void doHandleInvalid(ContextChangeEvent event, List<Scheduled> scheduled) {
- // nothing to do in default computation
- }
-
- public void handleInvalid(ContextChangeEvent event, List<Scheduled> scheduled) {
- String name = event.getName();
- EclipseContext context = (EclipseContext) event.getContext();
-
- stopListening(context, name);
- doHandleInvalid(event, scheduled);
- }
-
- /**
- * Remove this computation from all contexts that are tracking it
- */
- protected void removeAll() {
- for (EclipseContext c : dependencies.keySet()) {
- c.removeListener(this);
- }
- dependencies.clear();
- }
-
- public void startListening() {
- for (EclipseContext c : dependencies.keySet()) {
- c.addListener(this, dependencies.get(c));
- }
+ public void handleInvalid(ContextChangeEvent event, Set<Scheduled> scheduled) {
+ invalidateComputation();
}
- public void stopListening(EclipseContext context, String name) {
- if (context == null) {
- Set<EclipseContext> dependentContexts = dependencies.keySet();
- for (EclipseContext dependentContext : dependentContexts) {
- dependentContext.removeListener(this);
- }
- return;
- }
- if (name == null) {
- dependencies.remove(context);
- context.removeListener(this);
- return;
- }
- Set<String> properties = dependencies.get(context);
- if (properties != null) {
- properties.remove(name);
- // if we no longer track any values in the context, remove dependency
- if (properties.isEmpty()) {
- dependencies.remove(context);
- context.removeListener(this);
- }
- }
+ public boolean isValid() {
+ return validComputation;
}
- public Set<String> dependsOnNames(IEclipseContext context) {
- return dependencies.get(context);
+ public void invalidateComputation() {
+ validComputation = false;
}
} \ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextObjectSupplier.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextObjectSupplier.java
index 6a26d00..2e21e07 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextObjectSupplier.java
@@ -12,6 +12,7 @@ package org.eclipse.e4.core.internal.contexts;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.Stack;
import javax.inject.Named;
import org.eclipse.e4.core.contexts.Active;
import org.eclipse.e4.core.contexts.IEclipseContext;
@@ -122,9 +123,6 @@ public class ContextObjectSupplier extends PrimaryObjectSupplier {
final private IEclipseContext context;
- private Computation outerComputation;
- private int paused = 0;
-
public ContextObjectSupplier(IEclipseContext context, IInjector injector) {
this.context = context;
}
@@ -205,16 +203,15 @@ public class ContextObjectSupplier extends PrimaryObjectSupplier {
}
synchronized public void pauseRecording() {
- if (paused == 0)
- outerComputation = EclipseContext.localComputation().get();
- EclipseContext.localComputation().set(null);
- paused++;
+ Stack<Computation> current = EclipseContext.getCalculatedComputations();
+ current.push(null);
}
synchronized public void resumeRecoding() {
- paused--;
- if (paused == 0)
- EclipseContext.localComputation().set(outerComputation);
+ Stack<Computation> current = EclipseContext.getCalculatedComputations();
+ Computation plug = current.pop();
+ if (plug != null)
+ throw new IllegalArgumentException("Internal error in nested computation processing");
}
static public ContextObjectSupplier getObjectSupplier(IEclipseContext context, IInjector injector) {
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
index 3ae8acf..a68061d 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * Copyright (c) 2009, 2011 IBM Corporation 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
@@ -12,13 +12,17 @@ package org.eclipse.e4.core.internal.contexts;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
+import java.util.Vector;
import org.eclipse.e4.core.contexts.IContextFunction;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.contexts.RunAndTrack;
@@ -69,11 +73,10 @@ public class EclipseContext implements IEclipseContext {
}
}
- static ThreadLocal<Computation> currentComputation = new ThreadLocal<Computation>();
+ private Map<String, Vector<WeakReference<Computation>>> listeners = Collections.synchronizedMap(new HashMap<String, Vector<WeakReference<Computation>>>());
+ private Map<String, ValueComputation> localValueComputations = Collections.synchronizedMap(new HashMap<String, ValueComputation>());
+ private Set<Computation> activeRATs = new HashSet<Computation>();
- private Map<String, Set<Computation>> listeners = Collections.synchronizedMap(new HashMap<String, Set<Computation>>());
-
- final Map<String, ValueComputation> localValueComputations = Collections.synchronizedMap(new HashMap<String, ValueComputation>());
final Map<String, Object> localValues = Collections.synchronizedMap(new HashMap<String, Object>());
private final ILookupStrategy strategy;
@@ -86,6 +89,8 @@ public class EclipseContext implements IEclipseContext {
private Set<IContextDisposalListener> notifyOnDisposal = new HashSet<IContextDisposalListener>();
+ static private ThreadLocal<Stack<Computation>> currentComputation = new ThreadLocal<Stack<Computation>>();
+
/**
* A context key (value "activeChildContext") that identifies another {@link IEclipseContext}
* that is a child of the context. The meaning of active is up to the application.
@@ -167,11 +172,8 @@ public class EclipseContext implements IEclipseContext {
}
ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.DISPOSE, null, null, null);
- List<Scheduled> scheduled = new ArrayList<Scheduled>();
- Set<Computation> allComputations = new HashSet<Computation>();
- for (Set<Computation> computations : listeners.values()) {
- allComputations.addAll(computations);
- }
+ Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
+ Set<Computation> allComputations = getListeners();
listeners.clear();
for (Computation computation : allComputations) {
computation.handleInvalid(event, scheduled);
@@ -216,9 +218,8 @@ public class EclipseContext implements IEclipseContext {
trackAccess(name);
if (this == originatingContext) {
ValueComputation valueComputation = localValueComputations.get(name);
- if (valueComputation != null) {
+ if (valueComputation != null && valueComputation.isValid())
return valueComputation.get();
- }
}
Object result = null;
@@ -233,18 +234,21 @@ public class EclipseContext implements IEclipseContext {
// if we found something, compute the concrete value and return
if (result != null) {
if (result instanceof IContextFunction) {
- ValueComputation valueComputation = new ValueComputation(this, originatingContext, name, ((IContextFunction) result));
+ ValueComputation valueComputation = new ValueComputation(name, originatingContext, ((IContextFunction) result));
+
+ // do calculations before adding listeners
+ result = valueComputation.get();
+
originatingContext.localValueComputations.put(name, valueComputation);
- // the cached value depends on all entries with this name and all parent relationships
- // between the originating context and this context, inclusive
+ // need to manually add dependency as the computation haven't being created yet at the time
+ // we walked context hierarchy to find its definition
for (EclipseContext step = originatingContext; step != null; step = step.getParent()) {
- valueComputation.addDependency(step, name);
+ step.addDependency(name, valueComputation);
if (step == this)
break;
- valueComputation.addDependency(step, PARENT);
+ step.addDependency(PARENT, valueComputation);
}
- result = valueComputation.get();
}
return result;
}
@@ -262,26 +266,33 @@ public class EclipseContext implements IEclipseContext {
* The given name has been modified or removed in this context. Invalidate all local value
* computations and listeners that depend on this name.
*/
- public void invalidate(String name, int eventType, Object oldValue, List<Scheduled> scheduled) {
- if (DebugHelper.DEBUG_NAMES)
- System.out.println("[context] invalidating \"" + name + "\" on " + toString()); //$NON-NLS-1$ //$NON-NLS-2$
- removeLocalValueComputations(name);
- handleInvalid(name, eventType, oldValue, scheduled);
- }
-
- /**
- * The value of the given name has changed in this context. This either means the value has been
- * changed directly, or the value is a function that has been invalidated (one of the function's
- * dependencies has changed).
- */
- void handleInvalid(String name, int eventType, Object oldValue, List<Scheduled> scheduled) {
- Set<Computation> computations = listeners.remove(name);
- if (computations == null)
- return;
- ContextChangeEvent event = new ContextChangeEvent(this, eventType, null, name, oldValue);
- for (Computation computation : computations) {
+ public void invalidate(String name, int eventType, Object oldValue, Set<Scheduled> scheduled) {
+ ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.ADDED, null, name, oldValue);
+ ValueComputation computation = localValueComputations.get(name);
+ if (computation != null && computation.isValid()) {
computation.handleInvalid(event, scheduled);
}
+ Vector<WeakReference<Computation>> namedComputations = listeners.get(name);
+ if (namedComputations != null) {
+ int invalidListenersCount = 0;
+ for (WeakReference<Computation> listenerRef : namedComputations) {
+ Computation listener = listenerRef.get();
+ if (listener != null && listener.isValid())
+ listener.handleInvalid(event, scheduled);
+ else
+ invalidListenersCount++;
+ }
+ // more than half of listeners are invalid, clean the listener list
+ if ((invalidListenersCount << 2) > namedComputations.size()) {
+ Vector<WeakReference<Computation>> tmp = new Vector<WeakReference<Computation>>(namedComputations.size() - invalidListenersCount);
+ for (WeakReference<Computation> listenerRef : namedComputations) {
+ Computation listener = listenerRef.get();
+ if (listener != null && listener.isValid())
+ tmp.add(listenerRef);
+ }
+ listeners.put(name, tmp);
+ }
+ }
}
private boolean isSetLocally(String name) {
@@ -292,37 +303,27 @@ public class EclipseContext implements IEclipseContext {
public void remove(String name) {
if (isSetLocally(name)) {
Object oldValue = localValues.remove(name);
- List<Scheduled> scheduled = new ArrayList<Scheduled>();
+ Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
invalidate(name, ContextChangeEvent.REMOVED, oldValue, scheduled);
processScheduled(scheduled);
}
}
- /**
- * Removes all local value computations associated with the given name.
- * @param name The name to remove
- */
- public void removeLocalValueComputations(String name) {
- synchronized (localValueComputations) {
- ValueComputation removed = localValueComputations.remove(name);
- if (removed != null)
- removed.stopListening(null, name);
- }
- }
-
public void runAndTrack(final RunAndTrack runnable) {
- ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.INITIAL, null, null, null);
TrackableComputationExt computation = new TrackableComputationExt(runnable, this);
- computation.update(event);
+ ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.INITIAL, null, null, null);
+ boolean result = computation.update(event);
+ if (result)
+ activeRATs.add(computation);
+ }
+
+ public void removeRAT(Computation computation) {
+ activeRATs.remove(computation);
}
- protected void processScheduled(List<Scheduled> scheduledList) {
- HashSet<Scheduled> sent = new HashSet<Scheduled>(scheduledList.size());
+ protected void processScheduled(Set<Scheduled> scheduledList) {
for (Iterator<Scheduled> i = scheduledList.iterator(); i.hasNext();) {
Scheduled scheduled = i.next();
- // don't send the same event twice
- if (!sent.add(scheduled))
- continue;
scheduled.runnable.update(scheduled.event);
}
}
@@ -338,20 +339,20 @@ public class EclipseContext implements IEclipseContext {
boolean containsKey = localValues.containsKey(name);
Object oldValue = localValues.put(name, value);
if (!containsKey || value != oldValue) {
- List<Scheduled> scheduled = new ArrayList<Scheduled>();
+ Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
invalidate(name, ContextChangeEvent.ADDED, oldValue, scheduled);
processScheduled(scheduled);
}
}
public void modify(String name, Object value) {
- List<Scheduled> scheduled = new ArrayList<Scheduled>();
+ Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
if (!internalModify(name, value, scheduled))
set(name, value);
processScheduled(scheduled);
}
- public boolean internalModify(String name, Object value, List<Scheduled> scheduled) {
+ public boolean internalModify(String name, Object value, Set<Scheduled> scheduled) {
boolean containsKey = localValues.containsKey(name);
if (containsKey) {
if (!checkModifiable(name)) {
@@ -381,7 +382,7 @@ public class EclipseContext implements IEclipseContext {
return; // no-op
if (parentContext != null)
parentContext.removeChild(this);
- List<Scheduled> scheduled = new ArrayList<Scheduled>();
+ Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
handleReparent((EclipseContext) parent, scheduled);
localValues.put(PARENT, parent);
if (parent != null)
@@ -399,10 +400,22 @@ public class EclipseContext implements IEclipseContext {
}
private void trackAccess(String name) {
- Computation computation = currentComputation.get();
- if (computation != null) {
- computation.addDependency(this, name);
+ Stack<Computation> current = getCalculatedComputations();
+ if (current.isEmpty())
+ return;
+ Computation computation = current.peek(); // only track in the top-most one
+ if (computation == null)
+ return;
+ addDependency(name, computation);
+ }
+
+ public void addDependency(String name, Computation computation) {
+ Vector<WeakReference<Computation>> nameListeners = listeners.get(name);
+ if (nameListeners == null) {
+ nameListeners = new Vector<WeakReference<Computation>>();
+ listeners.put(name, nameListeners);
}
+ nameListeners.add(new WeakReference<Computation>(computation));
}
public void declareModifiable(String name) {
@@ -431,16 +444,28 @@ public class EclipseContext implements IEclipseContext {
if (object == null)
return;
ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.UNINJECTED, new Object[] {object}, null, null);
- // TBD computation here removes listeners. We should do that inside this method instead
- Set<Computation> computations = getListeners();
- Computation[] ls = computations.toArray(new Computation[computations.size()]);
- for (Computation computation : ls) {
+ Set<Computation> comps = getListeners();
+ for (Computation computation : comps) {
if (computation instanceof TrackableComputationExt)
((TrackableComputationExt) computation).update(event);
}
}
- private void handleReparent(EclipseContext newParent, List<Scheduled> scheduled) {
+ public Set<Computation> getListeners() {
+ Collection<Vector<WeakReference<Computation>>> collection = listeners.values();
+ Set<Computation> comps = new HashSet<Computation>();
+
+ for (Vector<WeakReference<Computation>> set : collection) {
+ for (WeakReference<Computation> ref : set) {
+ Computation comp = ref.get();
+ if (comp != null && comp.isValid())
+ comps.add(comp);
+ }
+ }
+ return comps;
+ }
+
+ private void handleReparent(EclipseContext newParent, Set<Scheduled> scheduled) {
// TBD should we lock waiting list while doing reparent?
// Add "boolean inReparent" on the root context and process right away?
processWaiting();
@@ -460,6 +485,7 @@ public class EclipseContext implements IEclipseContext {
invalidate(name, ContextChangeEvent.ADDED, oldValue, scheduled);
}
localValueComputations.clear();
+ // XXX localValueComputations -> all invalidate
}
public void processWaiting() {
@@ -569,10 +595,6 @@ public class EclipseContext implements IEclipseContext {
}
}
- static public ThreadLocal<Computation> localComputation() {
- return currentComputation;
- }
-
public IEclipseContext getActiveChild() {
return (EclipseContext) internalGet(this, ACTIVE_CHILD, true);
}
@@ -638,7 +660,11 @@ public class EclipseContext implements IEclipseContext {
public Map<String, Object> cachedCachedContextFunctions() {
Map<String, Object> result = new HashMap<String, Object>(localValueComputations.size());
for (String string : localValueComputations.keySet()) {
- result.put(string, localValueComputations.get(string).get());
+ ValueComputation vc = localValueComputations.get(string);
+ if (vc == null)
+ continue;
+ if (vc.isValid())
+ result.put(string, localValueComputations.get(string).get());
}
return result;
}
@@ -653,38 +679,37 @@ public class EclipseContext implements IEclipseContext {
// This method is for debug only, do not use externally
public Set<Computation> getListeners(String name) {
- Set<Computation> tmp = listeners.get(name);
+ Vector<WeakReference<Computation>> tmp = listeners.get(name);
+ if (tmp == null)
+ return null;
Set<Computation> result = new HashSet<Computation>(tmp.size());
- result.addAll(tmp);
+ for (WeakReference<Computation> ref : tmp) {
+ Computation listener = ref.get();
+ if (listener != null && listener.isValid())
+ result.add(listener);
+ }
return result;
}
- public void addListener(Computation computation, Set<String> names) {
- for (String name : names) {
- if (listeners.containsKey(name)) {
- Set<Computation> existingDependencies = listeners.get(name);
- existingDependencies.add(computation);
- } else {
- Set<Computation> computations = new HashSet<Computation>();
- computations.add(computation);
- listeners.put(name, computations);
- }
+ static public Stack<Computation> getCalculatedComputations() {
+ Stack<Computation> current = currentComputation.get();
+ if (current == null) {
+ current = new Stack<Computation>();
+ currentComputation.set(current);
}
+ return current;
}
- public void removeListener(Computation computation) {
- for (Map.Entry<String, Set<Computation>> entry : listeners.entrySet()) {
- Set<Computation> computations = entry.getValue();
- computations.remove(computation);
- }
+ public void pushComputation(Computation comp) {
+ Stack<Computation> current = getCalculatedComputations();
+ current.push(comp);
}
- public Set<Computation> getListeners() {
- Set<Computation> computations = new HashSet<Computation>();
- for (Map.Entry<String, Set<Computation>> entry : listeners.entrySet()) {
- computations.addAll(entry.getValue());
- }
- return computations;
+ public void popComputation(Computation comp) {
+ Stack<Computation> current = getCalculatedComputations();
+ Computation ended = current.pop();
+ if (ended != comp)
+ throw new IllegalArgumentException("Internal error: Invalid nested computation processing"); //$NON-NLS-1$
}
}
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/TrackableComputationExt.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/TrackableComputationExt.java
index a45fa48..fcbd937 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/TrackableComputationExt.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/TrackableComputationExt.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.e4.core.internal.contexts;
-import java.util.List;
+import java.util.Set;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.contexts.RunAndTrack;
import org.eclipse.e4.core.internal.contexts.EclipseContext.Scheduled;
@@ -27,7 +27,11 @@ public class TrackableComputationExt extends Computation {
}
public int hashCode() {
- return 31 + ((runnable == null) ? 0 : runnable.hashCode());
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((originatingContext == null) ? 0 : originatingContext.hashCode());
+ result = prime * result + ((runnable == null) ? 0 : runnable.hashCode());
+ return result;
}
public boolean equals(Object obj) {
@@ -38,6 +42,11 @@ public class TrackableComputationExt extends Computation {
if (getClass() != obj.getClass())
return false;
TrackableComputationExt other = (TrackableComputationExt) obj;
+ if (originatingContext == null) {
+ if (other.originatingContext != null)
+ return false;
+ } else if (!originatingContext.equals(other.originatingContext))
+ return false;
if (runnable == null) {
if (other.runnable != null)
return false;
@@ -46,7 +55,8 @@ public class TrackableComputationExt extends Computation {
return true;
}
- protected void doHandleInvalid(ContextChangeEvent event, List<Scheduled> scheduledList) {
+ public void handleInvalid(ContextChangeEvent event, Set<Scheduled> scheduledList) {
+ // don't call super - we keep the link unless uninjected / disposed
int eventType = event.getEventType();
if (eventType == ContextChangeEvent.INITIAL || eventType == ContextChangeEvent.DISPOSE) {
// process right away
@@ -70,8 +80,7 @@ public class TrackableComputationExt extends Computation {
}
}
- Computation oldComputation = EclipseContext.localComputation().get();
- EclipseContext.localComputation().set(this);
+ ((EclipseContext) originatingContext).pushComputation(this);
boolean result = true;
try {
if (cachedEvent != null) {
@@ -81,7 +90,7 @@ public class TrackableComputationExt extends Computation {
cachedEvent = null;
} else {
if (eventType != ContextChangeEvent.DISPOSE && eventType != ContextChangeEvent.UNINJECTED) {
- result = runnable.changed(cachedEvent.getContext());
+ result = runnable.changed(originatingContext);
cachedEvent = null;
}
}
@@ -91,24 +100,25 @@ public class TrackableComputationExt extends Computation {
result = ((RunAndTrackExt) runnable).update(event.getContext(), event.getEventType(), event.getArguments());
else {
if (eventType != ContextChangeEvent.DISPOSE && eventType != ContextChangeEvent.UNINJECTED)
- result = runnable.changed(event.getContext());
+ result = runnable.changed(originatingContext);
}
}
} finally {
- EclipseContext.localComputation().set(oldComputation);
+ ((EclipseContext) originatingContext).popComputation(this);
}
EclipseContext eventsContext = (EclipseContext) event.getContext();
if (eventType == ContextChangeEvent.DISPOSE) {
if (originatingContext.equals(eventsContext)) {
- removeAll();
+ ((EclipseContext) originatingContext).removeRAT(this);
+ invalidateComputation();
return false;
}
}
- if (result)
- startListening();
- else
- removeAll();
+ if (!result) {
+ ((EclipseContext) originatingContext).removeRAT(this);
+ invalidateComputation();
+ }
return result;
}
@@ -116,11 +126,4 @@ public class TrackableComputationExt extends Computation {
return runnable.toString();
}
- public void startAccessRecording() {
- EclipseContext.localComputation().set(this);
- }
-
- public void stopAccessRecording() {
- EclipseContext.localComputation().set(null);
- }
}
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
index b55344a..af2fe1f 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
@@ -10,124 +10,54 @@
*******************************************************************************/
package org.eclipse.e4.core.internal.contexts;
-import java.util.List;
+import java.util.Set;
import org.eclipse.e4.core.contexts.IContextFunction;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.internal.contexts.EclipseContext.Scheduled;
public class ValueComputation extends Computation {
- static class CycleException extends RuntimeException {
- private static final long serialVersionUID = 1L;
- private final String cycleMessage;
+ final static private Object NotAValue = new Object();
- CycleException(String cycleMessage) {
- super("Cycle while computing value"); //$NON-NLS-1$
- this.cycleMessage = cycleMessage;
- }
-
- String getCycleMessage() {
- return cycleMessage;
- }
-
- public String toString() {
- return "\n" + cycleMessage + '\n'; //$NON-NLS-1$
- }
- }
-
- private Object cachedValue;
- private IEclipseContext context;
- private String name;
- private boolean valid;
+ private Object cachedValue = NotAValue;
private IContextFunction function;
private EclipseContext originatingContext;
private boolean computing; // cycle detection
+ private String name;
- public ValueComputation(IEclipseContext context, IEclipseContext originatingContext, String name, IContextFunction computedValue) {
- this.context = context;
+ public ValueComputation(String name, IEclipseContext originatingContext, IContextFunction computedValue) {
this.originatingContext = (EclipseContext) originatingContext;
- this.name = name;
this.function = computedValue;
+ this.name = name;
}
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((context == null) ? 0 : context.hashCode());
- result = prime * result + ((function == null) ? 0 : function.hashCode());
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + ((originatingContext == null) ? 0 : originatingContext.hashCode());
- return result;
- }
+ public void handleInvalid(ContextChangeEvent event, Set<Scheduled> scheduled) {
+ cachedValue = NotAValue;
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ValueComputation other = (ValueComputation) obj;
- if (context == null) {
- if (other.context != null)
- return false;
- } else if (!context.equals(other.context))
- return false;
- if (function == null) {
- if (other.function != null)
- return false;
- } else if (!function.equals(other.function))
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (originatingContext == null) {
- if (other.originatingContext != null)
- return false;
- } else if (!originatingContext.equals(other.originatingContext))
- return false;
- return true;
- }
+ if (name.equals(event.getName()))
+ invalidateComputation();
- protected void doHandleInvalid(ContextChangeEvent event, List<Scheduled> scheduled) {
- valid = false;
- cachedValue = null;
int eventType = event.getEventType();
- // if the originating context is being disposed, remove this value computation completely
- if (eventType == ContextChangeEvent.DISPOSE) {
- IEclipseContext eventsContext = event.getContext();
- if (originatingContext.equals(eventsContext)) {
- removeAll();
- return;
- }
- return;
- }
- if (event.getName().equals(name))
- originatingContext.removeLocalValueComputations(name);
originatingContext.invalidate(name, eventType == ContextChangeEvent.DISPOSE ? ContextChangeEvent.REMOVED : eventType, event.getOldValue(), scheduled);
}
public Object get() {
- if (valid)
+ if (!isValid())
+ throw new IllegalArgumentException("Reusing invalidated computation"); //$NON-NLS-1$
+ if (cachedValue != NotAValue)
return cachedValue;
if (this.computing)
- throw new CycleException(this.toString());
+ throw new RuntimeException("Cycle while computing value" + this.toString()); //$NON-NLS-1$
- Computation oldComputation = EclipseContext.currentComputation.get();
- EclipseContext.currentComputation.set(this);
+ originatingContext.pushComputation(this);
computing = true;
try {
cachedValue = function.compute(originatingContext);
- valid = true;
- } catch (CycleException ex) {
- throw new CycleException(ex.getCycleMessage() + '\n' + this.toString());
+ validComputation = true;
} finally {
computing = false;
- EclipseContext.currentComputation.set(oldComputation);
+ originatingContext.popComputation(this);
}
- startListening();
return cachedValue;
}