1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-05 15:25:49 +02:00

[243794] - [update policy] VM Cache can save updates after they were canceled.

This commit is contained in:
Pawel Piech 2008-08-11 17:53:08 +00:00
parent eeb6b080ef
commit 4edc3e01e0
9 changed files with 329 additions and 132 deletions

View file

@ -0,0 +1,5 @@
org.eclipse.dd.dsf.ui/debug = false
org.eclipse.dd.dsf.ui/debug/vm/contentProvider = false
org.eclipse.dd.dsf.ui/debug/vm/delta = false
org.eclipse.dd.dsf.ui/debug/vm/cache = false
org.eclipse.dd.dsf.ui/debug/vm/presentationId =

View file

@ -10,6 +10,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.dsf.internal.ui; package org.eclipse.dd.dsf.internal.ui;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
@ -26,6 +27,8 @@ public class DsfUIPlugin extends AbstractUIPlugin {
private static BundleContext fgBundleContext; private static BundleContext fgBundleContext;
public static boolean DEBUG = false;
/** /**
* The constructor * The constructor
*/ */
@ -41,6 +44,7 @@ public class DsfUIPlugin extends AbstractUIPlugin {
public void start(BundleContext context) throws Exception { public void start(BundleContext context) throws Exception {
fgBundleContext = context; fgBundleContext = context;
super.start(context); super.start(context);
DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.dd.dsf.ui/debug")); //$NON-NLS-1$//$NON-NLS-2$
} }
/* /*
@ -66,5 +70,16 @@ public class DsfUIPlugin extends AbstractUIPlugin {
public static BundleContext getBundleContext() { public static BundleContext getBundleContext() {
return fgBundleContext; return fgBundleContext;
} }
/**
* If the debug flag is set the specified message is printed to the console
* @param message
*/
public static void debug(String message) {
if (DEBUG) {
System.out.println(message);
}
}
} }

View file

@ -15,15 +15,16 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.concurrent.SimpleDisplayExecutor; import org.eclipse.dd.dsf.ui.concurrent.SimpleDisplayExecutor;
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
@ -63,7 +64,23 @@ import org.eclipse.swt.widgets.Display;
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
abstract public class AbstractVMProvider implements IVMProvider, IVMEventListener abstract public class AbstractVMProvider implements IVMProvider, IVMEventListener
{ {
// debug flags
public static String DEBUG_PRESENTATION_ID = null;
public static boolean DEBUG_CONTENT_PROVIDER = false;
public static boolean DEBUG_DELTA = false;
static {
DEBUG_PRESENTATION_ID = Platform.getDebugOption("org.eclipse.dd.dsf.ui/debug/vm/presentationId"); //$NON-NLS-1$
if (!DsfUIPlugin.DEBUG || "".equals(DEBUG_PRESENTATION_ID)) { //$NON-NLS-1$
DEBUG_PRESENTATION_ID = null;
}
DEBUG_CONTENT_PROVIDER = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.dd.dsf.ui/debug/vm/contentProvider")); //$NON-NLS-1$
DEBUG_DELTA = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.dd.dsf.ui/debug/vm/delta")); //$NON-NLS-1$
}
/** Reference to the VM adapter that owns this provider */ /** Reference to the VM adapter that owns this provider */
private final AbstractVMAdapter fVMAdapter; private final AbstractVMAdapter fVMAdapter;
@ -126,12 +143,22 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
*/ */
private IRootVMNode fRootNode; private IRootVMNode fRootNode;
private class ModelProxyEventQueue { private class EventInfo {
private boolean fProcessingEvent = false; EventInfo(Object event, RequestMonitor rm) {
private List<Object> fEventQueue = new LinkedList<Object>(); fEvent = event;
fClientRm = rm;
}
Object fEvent;
RequestMonitor fClientRm;
} }
private Map<IVMModelProxy, ModelProxyEventQueue> fEventQueues = new HashMap<IVMModelProxy, ModelProxyEventQueue>(); private class ModelProxyEventQueue {
EventInfo fCurrentEvent = null;
RequestMonitor fCurrentRm = null;
List<EventInfo> fEventQueue = new LinkedList<EventInfo>();
}
private Map<IVMModelProxy, ModelProxyEventQueue> fProxyEventQueues = new HashMap<IVMModelProxy, ModelProxyEventQueue>();
/** /**
* Constructs the view model provider for given DSF session. The * Constructs the view model provider for given DSF session. The
@ -220,25 +247,47 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
for (final IVMModelProxy proxyStrategy : activeModelProxies) { for (final IVMModelProxy proxyStrategy : activeModelProxies) {
if (proxyStrategy.isDeltaEvent(event)) { if (proxyStrategy.isDeltaEvent(event)) {
if (!fEventQueues.containsKey(proxyStrategy)) { if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
fEventQueues.put(proxyStrategy, new ModelProxyEventQueue()); DsfUIPlugin.debug("eventReceived(proxyRoot = " + proxyStrategy .getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
} }
final ModelProxyEventQueue queue = fEventQueues.get(proxyStrategy); if (!fProxyEventQueues.containsKey(proxyStrategy)) {
if (queue.fProcessingEvent) { fProxyEventQueues.put(proxyStrategy, new ModelProxyEventQueue());
if (!queue.fEventQueue.isEmpty()) { if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
for (ListIterator<Object> itr = queue.fEventQueue.listIterator(queue.fEventQueue.size() - 1); itr.hasPrevious();) { DsfUIPlugin.debug("eventQueued(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
Object eventToSkip = itr.previous(); }
if (canSkipHandlingEvent(event, eventToSkip)) { }
itr.remove(); final ModelProxyEventQueue queue = fProxyEventQueues.get(proxyStrategy);
} else { if (queue.fCurrentEvent != null) {
break; assert queue.fCurrentRm != null;
// Iterate through the events in the queue and check if
// they can be skipped. If they can be skipped, then just
// mark their RM as done. Stop iterating through the queue
// if an event that cannot be skipped is encountered.
while (!queue.fEventQueue.isEmpty()) {
EventInfo eventToSkipInfo = queue.fEventQueue.get(queue.fEventQueue.size() - 1);
if (canSkipHandlingEvent(event, eventToSkipInfo.fEvent)) {
if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("eventSkipped(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + eventToSkipInfo + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
} }
queue.fEventQueue.remove(queue.fEventQueue.size() - 1);
eventToSkipInfo.fClientRm.done();
} else {
break;
} }
} }
crm.done(); // If the queue is empty check if the current event
queue.fEventQueue.add(event); // being processed can be skipped. If so, cancel its
// processing
if (queue.fEventQueue.isEmpty() && canSkipHandlingEvent(event, queue.fCurrentEvent.fEvent)) {
if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("eventCancelled(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + queue.fCurrentEvent + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
queue.fCurrentRm.cancel();
}
queue.fEventQueue.add(new EventInfo(event, crm));
} else { } else {
doHandleEvent(queue, proxyStrategy, event, crm); doHandleEvent(queue, proxyStrategy, new EventInfo(event, crm));
} }
} else { } else {
crm.done(); crm.done();
@ -247,28 +296,30 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
// Clean up model proxies that were removed. // Clean up model proxies that were removed.
List<IVMModelProxy> activeProxies = getActiveModelProxies(); List<IVMModelProxy> activeProxies = getActiveModelProxies();
for (Iterator<IVMModelProxy> itr = fEventQueues.keySet().iterator(); itr.hasNext();) { for (Iterator<IVMModelProxy> itr = fProxyEventQueues.keySet().iterator(); itr.hasNext();) {
if (!activeProxies.contains(itr.next())) { if (!activeProxies.contains(itr.next())) {
itr.remove(); itr.remove();
} }
} }
} }
private void doHandleEvent(final ModelProxyEventQueue queue, final IVMModelProxy proxyStrategy, final Object event, final RequestMonitor rm) { private void doHandleEvent(final ModelProxyEventQueue queue, final IVMModelProxy proxyStrategy, final EventInfo eventInfo) {
queue.fProcessingEvent = true; assert queue.fCurrentEvent == null && queue.fCurrentRm == null;
handleEvent(
proxyStrategy, event, queue.fCurrentEvent = eventInfo;
new RequestMonitor(getExecutor(), null) { queue.fCurrentRm = new RequestMonitor(getExecutor(), null) {
@Override @Override
protected void handleCompleted() { protected void handleCompleted() {
queue.fProcessingEvent = false; queue.fCurrentEvent = null;
if (!queue.fEventQueue.isEmpty()) { queue.fCurrentRm = null;
doHandleEvent(queue, proxyStrategy, queue.fEventQueue.remove(0), rm); if (!queue.fEventQueue.isEmpty()) {
} else { EventInfo eventInfo = queue.fEventQueue.remove(0);
rm.done(); doHandleEvent(queue, proxyStrategy, eventInfo);
} }
} eventInfo.fClientRm.done();
}); }
};
handleEvent(proxyStrategy, eventInfo.fEvent, queue.fCurrentRm);
} }
/** /**
@ -287,6 +338,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
*/ */
protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
if (!proxyStrategy.isDisposed()) { if (!proxyStrategy.isDisposed()) {
if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("eventProcessing(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
proxyStrategy.createDelta( proxyStrategy.createDelta(
event, event,
new DataRequestMonitor<IModelDelta>(getExecutor(), rm) { new DataRequestMonitor<IModelDelta>(getExecutor(), rm) {
@ -294,6 +348,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
public void handleCompleted() { public void handleCompleted() {
if (isSuccess()) { if (isSuccess()) {
proxyStrategy.fireModelChanged(getData()); proxyStrategy.fireModelChanged(getData());
if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("eventDeltaFired(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
} }
super.handleCompleted(); super.handleCompleted();
} }
@ -439,6 +496,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
IHasChildrenUpdate[] updateProxies = new IHasChildrenUpdate[updates.length]; IHasChildrenUpdate[] updateProxies = new IHasChildrenUpdate[updates.length];
for (int i = 0; i < updates.length; i++) { for (int i = 0; i < updates.length; i++) {
final IHasChildrenUpdate update = updates[i]; final IHasChildrenUpdate update = updates[i];
if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("updateNodeHasChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
updateProxies[i] = new VMHasChildrenUpdate( updateProxies[i] = new VMHasChildrenUpdate(
update, update,
new ViewerDataRequestMonitor<Boolean>(getExecutor(), updates[i]) { new ViewerDataRequestMonitor<Boolean>(getExecutor(), updates[i]) {
@ -451,6 +511,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
@Override @Override
protected void handleErrorOrWarning() { protected void handleErrorOrWarning() {
if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) {
if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("not-supported:updateNodeHasChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
updateNode( updateNode(
node, node,
new VMChildrenUpdate( new VMChildrenUpdate(
@ -484,6 +547,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
* a cache. * a cache.
*/ */
public void updateNode(final IVMNode node, final IChildrenCountUpdate update) { public void updateNode(final IVMNode node, final IChildrenCountUpdate update) {
if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("updateNodeChildCount(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
node.update(new IChildrenCountUpdate[] { node.update(new IChildrenCountUpdate[] {
new VMChildrenCountUpdate( new VMChildrenCountUpdate(
update, update,
@ -497,6 +563,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
@Override @Override
protected void handleErrorOrWarning() { protected void handleErrorOrWarning() {
if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) {
if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("not-supported:updateNodeChildCount(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
updateNode( updateNode(
node, node,
new VMChildrenUpdate( new VMChildrenUpdate(
@ -527,6 +596,9 @@ abstract public class AbstractVMProvider implements IVMProvider, IVMEventListene
* a cache. * a cache.
*/ */
public void updateNode(IVMNode node, IChildrenUpdate update) { public void updateNode(IVMNode node, IChildrenUpdate update) {
if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("updateNodeChildren(node = " + node + ", update = " + update + ")");
}
node.update(new IChildrenUpdate[] { update }); node.update(new IChildrenUpdate[] { update });
} }

View file

@ -17,7 +17,6 @@ import java.util.Map;
import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
@ -63,16 +62,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
private ListenerList fListeners = new ListenerList(); private ListenerList fListeners = new ListenerList();
private IDoubleClickListener fDoubleClickListener; private IDoubleClickListener fDoubleClickListener;
/**
* Debug flag indicating whether the deltas should be traced in stdout.
*/
private static boolean DEBUG_DELTAS = false;
static {
DEBUG_DELTAS = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/deltas")); //$NON-NLS-1$
}
/** /**
* Creates this model proxy strategy for the given provider. * Creates this model proxy strategy for the given provider.
*/ */
@ -122,9 +111,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
public void fireModelChanged(IModelDelta delta) { public void fireModelChanged(IModelDelta delta) {
final IModelDelta root = getRootDelta(delta); final IModelDelta root = getRootDelta(delta);
Object[] listeners = getListeners(); Object[] listeners = getListeners();
if (DEBUG_DELTAS) {
DebugUIPlugin.debug("FIRE DELTA: " + delta.toString()); //$NON-NLS-1$
}
for (int i = 0; i < listeners.length; i++) { for (int i = 0; i < listeners.length; i++) {
final IModelChangedListener listener = (IModelChangedListener) listeners[i]; final IModelChangedListener listener = (IModelChangedListener) listeners[i];
ISafeRunnable safeRunnable = new ISafeRunnable() { ISafeRunnable safeRunnable = new ISafeRunnable() {
@ -353,6 +339,8 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
// super-class to resort to the default behavior which may add a // super-class to resort to the default behavior which may add a
// delta for every element in this node. // delta for every element in this node.
buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm); buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm);
} else {
super.handleCompleted();
} }
} }
}); });
@ -388,13 +376,13 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
node, node,
new VMChildrenUpdate( new VMChildrenUpdate(
parentDelta, getVMProvider().getPresentationContext(), -1, -1, parentDelta, getVMProvider().getPresentationContext(), -1, -1,
new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), null) { new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), requestMonitor) {
@Override @Override
protected void handleCompleted() { protected void handleSuccess() {
// Check for an empty list of elements. If it's empty then we // Check for an empty list of elements. If it's empty then we
// don't have to call the children nodes, so return here. // don't have to call the children nodes, so return here.
// No need to propagate error, there's no means or need to display it. // No need to propagate error, there's no means or need to display it.
if (!isSuccess() || getData().isEmpty()) { if (getData().isEmpty()) {
requestMonitor.done(); requestMonitor.done();
return; return;
} }
@ -490,13 +478,12 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
parentDelta, getVMProvider().getPresentationContext(), -1, -1, parentDelta, getVMProvider().getPresentationContext(), -1, -1,
new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), requestMonitor) { new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), requestMonitor) {
@Override @Override
protected void handleCompleted() { protected void handleSuccess() {
if (fDisposed) return; if (fDisposed) return;
// Check for an empty list of elements. If it's empty then we // Check for an empty list of elements. If it's empty then we
// don't have to call the children nodes, so return here. // don't have to call the children nodes, so return here.
// No need to propagate error, there's no means or need to display it. if (getData().size() == 0) {
if (!isSuccess() || getData().size() == 0) {
requestMonitor.done(); requestMonitor.done();
return; return;
} }
@ -556,7 +543,7 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
node, delta, calculateOffsets, node, delta, calculateOffsets,
new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), requestMonitor) { new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), requestMonitor) {
@Override @Override
protected void handleCompleted() { protected void handleSuccess() {
final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor); final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
int multiRmCount = 0; int multiRmCount = 0;

View file

@ -45,6 +45,11 @@ public class VMChildrenCountUpdate extends VMViewerUpdate implements IChildrenCo
fCountRequestMonitor.setData(count); fCountRequestMonitor.setData(count);
} }
@Override
public String toString() {
return "VMChildrenCountUpdate: " + getElement(); //$NON-NLS-1$
}
@Override @Override
public void done() { public void done() {
assert isCanceled() || fCountRequestMonitor.getData() != null || !fCountRequestMonitor.isSuccess(); assert isCanceled() || fCountRequestMonitor.getData() != null || !fCountRequestMonitor.isSuccess();

View file

@ -13,11 +13,7 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
@ -92,7 +88,7 @@ public class VMChildrenUpdate extends VMViewerUpdate implements IChildrenUpdate
@Override @Override
public String toString() { public String toString() {
return "VMElementsUpdate for elements under parent = " + getElement() + ", in range " + getOffset() + " -> " + (getOffset() + getLength()); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ return "VMChildrenUpdate:" + getElement() + " {"+ getOffset() + "->" + (getOffset() + getLength()) + "}"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
} }
@Override @Override
@ -105,32 +101,21 @@ public class VMChildrenUpdate extends VMViewerUpdate implements IChildrenUpdate
* A flexible hierarchy bug/optimization causes query with incorrect * A flexible hierarchy bug/optimization causes query with incorrect
* IChildrenUpdate[] array length. * IChildrenUpdate[] array length.
* *
* We found this while deleting a register node. Example: * The problem manifests itself while deleting a register node.
* * For example, if the register view displays:
* the register view displays:
* PC * PC
* EAX * EAX
* EBX * EBX
* ECX * ECX
* EDX * EDX
* * And EBX is deleted, forcing a refresh, the viewer will query
* we delete EBX and force a context refresh. * for IChildrenUpdate[5] and IChildrenCountUpdate at the same time.
* *
* flexible hierarchy queries for IChildrenUpdate[5] and IChildrenCountUpdate at * To avoid this problem do not generate an error if the list of
* the same time. * children is smaller than the list of requested indexes. Also,
* * do not check if any of the elements are null.
* VMElementsUpdate, used by VMCache to wrap the IChildrenUpdate, generates an
* IStatus.ERROR with message "Incomplete elements of updates" when fElements
* count (provided by service) does not match the length provided by the original
* update query.
*
* Workaround, always set the elements array in the request monitor, but still set
* the error status.
*/ */
rm.setData(fElements); rm.setData(fElements);
if (rm.isSuccess() && fLength != -1 && fElements.size() != fLength) {
rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Incomplete elements of updates", null)); //$NON-NLS-1$
}
super.done(); super.done();
} }

View file

@ -46,6 +46,11 @@ public class VMHasChildrenUpdate extends VMViewerUpdate implements IHasChildrenU
fHasElemsRequestMonitor.setData(hasChildren); fHasElemsRequestMonitor.setData(hasChildren);
} }
@Override
public String toString() {
return "VMHasChildrenUpdate: " + getElement(); //$NON-NLS-1$
}
@Override @Override
public void done() { public void done() {
assert isCanceled() || fHasElemsRequestMonitor.getData() != null || !fHasElemsRequestMonitor.isSuccess(); assert isCanceled() || fHasElemsRequestMonitor.getData() != null || !fHasElemsRequestMonitor.isSuccess();

View file

@ -20,6 +20,7 @@ import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable; import org.eclipse.dd.dsf.concurrent.DsfRunnable;
@ -27,6 +28,7 @@ import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData; import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMService; import org.eclipse.dd.dsf.datamodel.IDMService;
import org.eclipse.dd.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.concurrent.ViewerCountingRequestMonitor; import org.eclipse.dd.dsf.ui.concurrent.ViewerCountingRequestMonitor;
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
@ -53,6 +55,14 @@ import org.eclipse.jface.viewers.TreePath;
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
public class AbstractCachingVMProvider extends AbstractVMProvider implements ICachingVMProvider { public class AbstractCachingVMProvider extends AbstractVMProvider implements ICachingVMProvider {
// debug flags
public static boolean DEBUG_CACHE = false;
static {
DEBUG_CACHE = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.dd.dsf.ui/debug/vm/cache")); //$NON-NLS-1$
}
private static final int MAX_CACHE_SIZE = 1000; private static final int MAX_CACHE_SIZE = 1000;
/** /**
@ -139,14 +149,60 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
super(key); super(key);
} }
/**
* Counter of flush operations performed on this entry. It is used
* by caching update operations to make sure that an update which
* was issued for a given entry is still valid for that entry when
* it is completed by the node.
*/
int fFlushCounter = 0;
/**
* Indicates that the data in this cache entry is out of date with
* the data on the target.
*/
Boolean fDirty = false; Boolean fDirty = false;
/**
* Cached {@link IHasChildrenUpdate} result.
*/
Boolean fHasChildren = null; Boolean fHasChildren = null;
/**
* Cached {@link IChildrenCountUpdate} result.
*/
Integer fChildrenCount = null; Integer fChildrenCount = null;
/**
* Flag indicating that all the children of the given element are
* alredy cached.
*/
boolean fAllChildrenKnown = false; boolean fAllChildrenKnown = false;
/**
* Map containing children of this element, keyed by child index.
*/
Map<Integer,Object> fChildren = null; Map<Integer,Object> fChildren = null;
/**
* Map of IDMData objects, keyed by the DM context.
*/
Map<IDMContext,Object> fDataOrStatus = new HashMap<IDMContext,Object>(1); Map<IDMContext,Object> fDataOrStatus = new HashMap<IDMContext,Object>(1);
/**
* Previous known value of the DM data objects.
*/
Map<IDMContext,IDMData> fArchiveData = new HashMap<IDMContext,IDMData>(1);; Map<IDMContext,IDMData> fArchiveData = new HashMap<IDMContext,IDMData>(1);;
void ensureChildrenMap() {
if (fChildren == null) {
Integer childrenCount = fChildrenCount;
childrenCount = childrenCount != null ? childrenCount : 0;
int capacity = Math.max((childrenCount.intValue() * 4)/3, 32);
fChildren = new HashMap<Integer,Object>(capacity);
}
}
@Override @Override
public String toString() { public String toString() {
return fKey.toString() + " = " + //$NON-NLS-1$ return fKey.toString() + " = " + //$NON-NLS-1$
@ -315,23 +371,38 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
@Override @Override
public void updateNode(IVMNode node, IHasChildrenUpdate[] updates) { public void updateNode(final IVMNode node, IHasChildrenUpdate[] updates) {
LinkedList <IHasChildrenUpdate> missUpdates = new LinkedList<IHasChildrenUpdate>(); LinkedList <IHasChildrenUpdate> missUpdates = new LinkedList<IHasChildrenUpdate>();
for(final IHasChildrenUpdate update : updates) { for(final IHasChildrenUpdate update : updates) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update); ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key); final ElementDataEntry entry = getElementDataEntry(key);
if (entry.fHasChildren != null) { if (entry.fHasChildren != null) {
// Cache Hit! Just return the value.
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheHitHasChildren(node = " + node + ", update = " + update + ", " + entry.fHasChildren + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
update.setHasChilren(entry.fHasChildren.booleanValue()); update.setHasChilren(entry.fHasChildren.booleanValue());
update.done(); update.done();
} else { } else {
// Cache miss! Save the flush counter of the entry and create a proxy update.
final int flushCounter = entry.fFlushCounter;
missUpdates.add( missUpdates.add(
new VMHasChildrenUpdate( new VMHasChildrenUpdate(
update, update,
new ViewerDataRequestMonitor<Boolean>(getExecutor(), update) { new ViewerDataRequestMonitor<Boolean>(getExecutor(), update) {
@Override @Override
protected void handleCompleted() { protected void handleCompleted() {
// Update completed. Write value to cache only if update successed
// and the cache entry wasn't flushed in the mean time.
if(isSuccess()) { if(isSuccess()) {
entry.fHasChildren = this.getData(); if (flushCounter == entry.fFlushCounter) {
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheSavedHasChildren(node = " + node + ", update = " + update + ", " + getData() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
entry.fHasChildren = this.getData();
}
update.setHasChilren(getData()); update.setHasChilren(getData());
} else { } else {
update.setStatus(getStatus()); update.setStatus(getStatus());
@ -342,26 +413,42 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
} }
// Issue all the update proxies with one call.
if (!missUpdates.isEmpty()) { if (!missUpdates.isEmpty()) {
super.updateNode(node, missUpdates.toArray(new IHasChildrenUpdate[missUpdates.size()])); super.updateNode(node, missUpdates.toArray(new IHasChildrenUpdate[missUpdates.size()]));
} }
} }
@Override @Override
public void updateNode(IVMNode node, final IChildrenCountUpdate update) { public void updateNode(final IVMNode node, final IChildrenCountUpdate update) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update); ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key); final ElementDataEntry entry = getElementDataEntry(key);
if(entry.fChildrenCount != null) { if(entry.fChildrenCount != null) {
// Cache Hit! Just return the value.
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheHitChildrenCount(node = " + node + ", update = " + update + ", " + entry.fChildrenCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
update.setChildCount(entry.fChildrenCount.intValue()); update.setChildCount(entry.fChildrenCount.intValue());
update.done(); update.done();
} else { } else {
// Cache miss! Save the flush counter of the entry and create a proxy update.
final int flushCounter = entry.fFlushCounter;
IChildrenCountUpdate updateProxy = new VMChildrenCountUpdate( IChildrenCountUpdate updateProxy = new VMChildrenCountUpdate(
update, update,
new ViewerDataRequestMonitor<Integer>(getExecutor(), update) { new ViewerDataRequestMonitor<Integer>(getExecutor(), update) {
@Override @Override
protected void handleCompleted() { protected void handleCompleted() {
// Update completed. Write value to cache only if update successed
// and the cache entry wasn't flushed in the mean time.
if(isSuccess()) { if(isSuccess()) {
entry.fChildrenCount = this.getData(); if (flushCounter == entry.fFlushCounter) {
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheSavedChildrenCount(node = " + node + ", update = " + update + ", " + getData() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
entry.fChildrenCount = this.getData();
}
update.setChildCount(getData()); update.setChildCount(getData());
} else { } else {
update.setStatus(getStatus()); update.setStatus(getStatus());
@ -374,61 +461,70 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
@Override @Override
public void updateNode(IVMNode node, final IChildrenUpdate update) { public void updateNode(final IVMNode node, final IChildrenUpdate update) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update); ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key); final ElementDataEntry entry = getElementDataEntry(key);
final int flushCounter = entry.fFlushCounter;
if (entry.fChildren == null || (update.getOffset() < 0 && !entry.fAllChildrenKnown)) { if (entry.fChildren == null || (update.getOffset() < 0 && !entry.fAllChildrenKnown)) {
// We need to retrieve all the children if we don't have any children information. // Need to retrieve all the children if there is no children information yet.
// Or if the client requested all children (offset = -1, length -1) and we have not // Or if the client requested all children (offset = -1, length -1) and all
// retrieved that before. // the children are not yet known.
IChildrenUpdate updateProxy = new VMChildrenUpdate( IChildrenUpdate updateProxy = new VMChildrenUpdate(
update, update.getOffset(), update.getLength(), update, update.getOffset(), update.getLength(),
new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update){ new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update){
@Override @Override
protected void handleCompleted() protected void handleSuccess() {
{ // Check if the update retrieved all children by specifying "offset = -1, length = -1"
// Workaround for a bug caused by an optimization in the viewer: int updateOffset = update.getOffset();
// The viewer may request more children then there are at a given level. if (updateOffset < 0)
// This causes the update to return with an error. {
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109 updateOffset = 0;
// Instead of checking isSuccess(), check getData() != null. if (entry.fFlushCounter == flushCounter) {
if(getData() != null && !isCanceled()) {
// Check if the udpate retrieved all children by specifying "offset = -1, length = -1"
int updateOffset = update.getOffset();
if (updateOffset < 0) {
updateOffset = 0;
entry.fAllChildrenKnown = true; entry.fAllChildrenKnown = true;
} }
}
// Estimate size of children map.
Integer childrenCount = entry.fChildrenCount; if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
childrenCount = childrenCount != null ? childrenCount : 0; DsfUIPlugin.debug("cacheSavedChildren(node = " + node + ", update = " + update + ", children = {" + updateOffset + "->" + (updateOffset + getData().size()) + "})"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
int capacity = Math.max((childrenCount.intValue() * 4)/3, 32); }
// Create a new map, but only if it hasn't been created yet by another update.
if (entry.fChildren == null) { if (flushCounter == entry.fFlushCounter) {
entry.fChildren = new HashMap<Integer,Object>(capacity); entry.ensureChildrenMap();
} }
// Set the children to map and update. // Set the children to map and update.
for(int j = 0; j < getData().size(); j++) { for(int j = 0; j < getData().size(); j++) {
int offset = updateOffset + j; int offset = updateOffset + j;
Object child = getData().get(j); Object child = getData().get(j);
if (child != null) { if (child != null) {
if (flushCounter == entry.fFlushCounter) {
entry.fChildren.put(offset, child); entry.fChildren.put(offset, child);
update.setChild(child, offset);
} }
update.setChild(child, offset);
} }
} }
update.done(); update.done();
} }
@Override
protected void handleCancel() {
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheCanceledChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
super.handleCancel();
}
}); });
super.updateNode(node, updateProxy); super.updateNode(node, updateProxy);
} else if (update.getOffset() < 0 ) { } else if (update.getOffset() < 0 ) {
// The update requested all children. Fill in all children assuming that // The update requested all children. Fill in all children assuming that
// the children array is complete. // the children array is complete.
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheHitChildren(node = " + node + ", update = " + update + ", children = " + entry.fChildren.keySet() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
// The following assert should never fail given the first if statement. // The following assert should never fail given the first if statement.
assert entry.fAllChildrenKnown; assert entry.fAllChildrenKnown;
@ -438,13 +534,15 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
update.done(); update.done();
} else { } else {
// Make the list of missing children. If we've retrieved the // Update for a partial list of children was requested.
// Iterate through the known children and make a list of missing
// indexes.
List<Integer> childrenMissingFromCache = new LinkedList<Integer>(); List<Integer> childrenMissingFromCache = new LinkedList<Integer>();
for (int i = update.getOffset(); i < update.getOffset() + update.getLength(); i++) { for (int i = update.getOffset(); i < update.getOffset() + update.getLength(); i++) {
childrenMissingFromCache.add(i); childrenMissingFromCache.add(i);
} }
// Fill in the known children from cache. // Write known children from cache into the update.
for(Integer position = update.getOffset(); position < update.getOffset() + update.getLength(); position++) { for(Integer position = update.getOffset(); position < update.getOffset() + update.getLength(); position++) {
Object child = entry.fChildren.get(position); Object child = entry.fChildren.get(position);
if (child != null) { if (child != null) {
@ -453,13 +551,15 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
} }
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cachePartialHitChildren(node = " + node + ", update = " + update + ", missing = " + childrenMissingFromCache + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
if (childrenMissingFromCache.size() > 0) { if (childrenMissingFromCache.size() > 0) {
// perform a partial update; we only have some of the children of the update request // Some children were not found in the cache, create separate
// proxy updates for the continuous ranges of missing children.
List<IChildrenUpdate> partialUpdates = new ArrayList<IChildrenUpdate>(2); List<IChildrenUpdate> partialUpdates = new ArrayList<IChildrenUpdate>(2);
final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getExecutor(), update); final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getExecutor(), update);
while(childrenMissingFromCache.size() > 0) while(childrenMissingFromCache.size() > 0)
{ {
final int offset = childrenMissingFromCache.get(0); final int offset = childrenMissingFromCache.get(0);
@ -475,10 +575,22 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
update, offset, length, update, offset, length,
new DataRequestMonitor<List<Object>>(getExecutor(), multiRm) { new DataRequestMonitor<List<Object>>(getExecutor(), multiRm) {
@Override @Override
protected void handleCompleted() { protected void handleSuccess() {
if (getData() != null) { // Only save the children to the cahce if the entry wasn't flushed.
for (int i = 0; i < getData().size(); i++) { if (flushCounter == entry.fFlushCounter) {
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cachePartialSaveChildren(node = " + node + ", update = " + update + ", saved = {" + offset + "->" + (offset + getData().size()) + "})"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
entry.ensureChildrenMap();
}
for (int i = 0; i < getData().size(); i++) {
if (getData().get(i) != null) {
update.setChild(getData().get(i), offset + i); update.setChild(getData().get(i), offset + i);
if (flushCounter == entry.fFlushCounter) {
// Only save the children to the cahce if the entry wasn't flushed.
entry.fChildren.put(offset + i, getData().get(i));
}
} }
} }
multiRm.done(); multiRm.done();
@ -491,7 +603,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
} }
multiRm.setDoneCount(partialUpdates.size()); multiRm.setDoneCount(partialUpdates.size());
} else { } else {
// we have all of the children in cache; return from cache // All children were found in cache. Compelte the update.
update.done(); update.done();
} }
} }
@ -506,6 +618,9 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
* @param archive * @param archive
*/ */
private void flush(FlushMarkerKey flushKey) { private void flush(FlushMarkerKey flushKey) {
if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
DsfUIPlugin.debug("cacheFlushing(" + flushKey + ")"); //$NON-NLS-1$ //$NON-NLS-2$
}
// For each entry that has the given context as a parent, perform the flush. // For each entry that has the given context as a parent, perform the flush.
// Iterate through the cache entries backwards. This means that we will be // Iterate through the cache entries backwards. This means that we will be
// iterating in order of most-recently-used to least-recently-used. // iterating in order of most-recently-used to least-recently-used.
@ -528,6 +643,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
// now. // now.
if (entryFlushKey.includes(flushKey)) { if (entryFlushKey.includes(flushKey)) {
break; break;
} }
} }
else if (entry instanceof ElementDataEntry) { else if (entry instanceof ElementDataEntry) {
@ -561,9 +677,11 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
entry.remove(); entry.remove();
} }
} }
elementDataEntry.fFlushCounter++;
elementDataEntry.fHasChildren = null; elementDataEntry.fHasChildren = null;
elementDataEntry.fChildrenCount = null; elementDataEntry.fChildrenCount = null;
elementDataEntry.fChildren = null; elementDataEntry.fChildren = null;
elementDataEntry.fAllChildrenKnown = false;
elementDataEntry.fDirty = false; elementDataEntry.fDirty = false;
} else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) { } else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) {
elementDataEntry.fDirty = true; elementDataEntry.fDirty = true;
@ -754,7 +872,9 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
entry.fDataOrStatus.put(dmc, getData()); entry.fDataOrStatus.put(dmc, getData());
rm.setData(getData()); rm.setData(getData());
} else { } else {
entry.fDataOrStatus.put(dmc, getStatus()); if (!isCanceled()) {
entry.fDataOrStatus.put(dmc, getStatus());
}
rm.setStatus(getStatus()); rm.setStatus(getStatus());
} }
rm.done(); rm.done();

View file

@ -136,7 +136,10 @@ public class RequestMonitor {
* Sets the status of the result of the request. If status is OK, this * Sets the status of the result of the request. If status is OK, this
* method does not need to be called. * method does not need to be called.
*/ */
public synchronized void setStatus(IStatus status) { fStatus = status; } public synchronized void setStatus(IStatus status) {
assert isCanceled() || status.getSeverity() != IStatus.CANCEL;
fStatus = status;
}
/** Returns the status of the completed method. */ /** Returns the status of the completed method. */
public synchronized IStatus getStatus() { public synchronized IStatus getStatus() {