aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Thun2011-01-27 15:28:30 (EST)
committerChris Aniszczyk2011-01-31 10:44:07 (EST)
commit29113c22054efe10092ce8ff5d6ea9710e325962 (patch)
tree485fc0533d268acad18d65103ff5f7ee52ccf0ec
parent342d00eb46190f7a6c7cfcbf91e0706778d31194 (diff)
downloadegit-29113c22054efe10092ce8ff5d6ea9710e325962.zip
egit-29113c22054efe10092ce8ff5d6ea9710e325962.tar.gz
egit-29113c22054efe10092ce8ff5d6ea9710e325962.tar.bz2
Introduce caching for resource decorationsrefs/changes/60/2360/2
With this change a simple caching mechanism for resource decorations is introduced that is based on two timestamps: one timestamp is resource-specific and the other one is valid for the entire workspace. There are mainly two types of events that GitLightWeightDecorator handles: on the one hand IResourceChangeEvent, an event that only affects a dedicated set of resources, and on the other hand various events that are related to the connected Git repository. The Git repository events are generic and thus result in firing a LabelProviderChangedEvent that is handled by views showing decorated content (e.g. package explorer). Before firing this event the timestamp on workspace-level now is updated to indicate that all cached decorations (with a lower timestamp) are invalid. When handling an IResourceChangeEvent the resource-specific timestamp is cleared. This means that the cached decoration for this specific resource is no longer valid. Afterwards the same generic LabelProviderChangedEvent is fired instead of an event for the dedicated set of changed resources. This allows every view to decide what to update instead of forcing an update of invisible resources as well - which was the case before. This leads to more re-decorations, but due to the fact that for all unchanged resources cached information is available, this is very fast and in the end avoids unnecessary decorations of invisible resources - as mentioned above. Change-Id: Iafd0fa15db3ec65d7ce8668f21819ec50733d820 Signed-off-by: Philipp Thun <philipp.thun@sap.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java116
1 files changed, 85 insertions, 31 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
index 253d81c..9ddc7e7 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
@@ -22,17 +22,18 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.egit.core.internal.util.ExceptionCollector;
import org.eclipse.egit.core.project.GitProjectData;
@@ -56,7 +57,6 @@ import org.eclipse.jgit.events.IndexChangedListener;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.events.RefsChangedListener;
-import org.eclipse.jgit.events.RepositoryEvent;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.osgi.util.TextProcessor;
@@ -90,6 +90,15 @@ public class GitLightweightDecorator extends LabelProvider implements
*/
public static final String DECORATOR_ID = "org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator"; //$NON-NLS-1$
+ private static final QualifiedName REFRESH_KEY = new QualifiedName(
+ Activator.getPluginId(), "refresh"); //$NON-NLS-1$
+
+ private static final QualifiedName REFRESHED_KEY = new QualifiedName(
+ Activator.getPluginId(), "refreshed"); //$NON-NLS-1$
+
+ private static final QualifiedName DECORATABLE_RESOURCE_KEY = new QualifiedName(
+ Activator.getPluginId(), "decoratableResource"); //$NON-NLS-1$
+
/**
* Bit-mask describing interesting changes for IResourceChangeListener
* events
@@ -195,7 +204,7 @@ public class GitLightweightDecorator extends LabelProvider implements
return;
// Don't decorate if UI plugin is not running
- Activator activator = Activator.getDefault();
+ final Activator activator = Activator.getDefault();
if (activator == null)
return;
@@ -206,9 +215,11 @@ public class GitLightweightDecorator extends LabelProvider implements
// Don't decorate non-existing resources
if (!resource.exists() && !resource.isPhantom())
return;
+
// Don't decorate ignored resources (e.g. bin folder content)
if (Team.isIgnoredHint(resource))
return;
+
// Make sure we're dealing with a project under Git revision control
final RepositoryMapping mapping = RepositoryMapping
.getMapping(resource);
@@ -220,13 +231,45 @@ public class GitLightweightDecorator extends LabelProvider implements
return;
try {
- DecorationHelper helper = new DecorationHelper(activator
- .getPreferenceStore());
- helper.decorate(decoration,
- new DecoratableResourceAdapter(resource));
+ IDecoratableResource decoratableResource = null;
+ final DecorationHelper helper = new DecorationHelper(
+ activator.getPreferenceStore());
+
+ final Long refreshed = (Long) resource
+ .getSessionProperty(REFRESHED_KEY);
+ if (refreshed != null) {
+ // Stored decoratable resource is available
+ final IWorkspaceRoot root = resource.getWorkspace().getRoot();
+ final Long refresh = (Long) root
+ .getSessionProperty(REFRESH_KEY);
+ if (refresh == null
+ || refresh.longValue() < refreshed.longValue()) {
+ // Stored decoratable resource is up-to-date
+ decoratableResource = (IDecoratableResource) resource
+ .getSessionProperty(DECORATABLE_RESOURCE_KEY);
+ if (decoratableResource != null) {
+ // Use stored decoratable resource
+ helper.decorate(decoration, decoratableResource);
+ return;
+ }
+ }
+ }
+
+ // No (up-to-date) stored decoratable resource is available
+ decoratableResource = new DecoratableResourceAdapter(resource);
+ helper.decorate(decoration, decoratableResource);
+
+ // Store decoratable resource in session
+ resource.setSessionProperty(DECORATABLE_RESOURCE_KEY,
+ decoratableResource);
+ // Set (new) 'refreshed' timestamp
+ resource.setSessionProperty(REFRESHED_KEY,
+ new Long(System.currentTimeMillis()));
} catch (IOException e) {
handleException(resource, new CoreException(new Status(
IStatus.ERROR, Activator.getPluginId(), e.getMessage(), e)));
+ } catch (CoreException e) {
+ handleException(resource, e);
}
}
@@ -654,34 +697,12 @@ public class GitLightweightDecorator extends LabelProvider implements
.toArray()));
}
- /**
- * Callback for RepositoryListener events
- *
- * We resolve the repository mapping for the changed repository and forward
- * that to repositoryChanged(RepositoryMapping).
- *
- * @param e
- * The original change event
- */
- private void repositoryChanged(RepositoryEvent e) {
- final Set<RepositoryMapping> ms = new HashSet<RepositoryMapping>();
- for (final IProject p : ResourcesPlugin.getWorkspace().getRoot()
- .getProjects()) {
- final RepositoryMapping mapping = RepositoryMapping.getMapping(p);
- if (mapping != null && mapping.getRepository() == e.getRepository())
- ms.add(mapping);
- }
- for (final RepositoryMapping m : ms) {
- repositoryChanged(m);
- }
- }
-
public void onIndexChanged(IndexChangedEvent e) {
- repositoryChanged(e);
+ postLabelEvent(new LabelProviderChangedEvent(this));
}
public void onRefsChanged(RefsChangedEvent e) {
- repositoryChanged(e);
+ postLabelEvent(new LabelProviderChangedEvent(this));
}
/**
@@ -728,6 +749,39 @@ public class GitLightweightDecorator extends LabelProvider implements
* The event to post
*/
private void postLabelEvent(final LabelProviderChangedEvent event) {
+ if (event.getElement() == null) {
+ // Update all elements
+ final IWorkspaceRoot root = ResourcesPlugin.getWorkspace()
+ .getRoot();
+ try {
+ // Set (new) 'refresh' timestamp
+ root.setSessionProperty(REFRESH_KEY,
+ new Long(System.currentTimeMillis()));
+ } catch (CoreException e) {
+ handleException(root, e);
+ }
+
+ fireLabelEvent(event);
+ } else {
+ // Update specific elements
+ Object[] elements = event.getElements();
+ for (Object element : elements) {
+ final IResource resource = getResource(element);
+ if (resource != null)
+ try {
+ // Remove 'refreshed' property
+ resource.setSessionProperty(REFRESHED_KEY, null);
+ } catch (CoreException e) {
+ // Ignore
+ }
+ }
+
+ // Fire a generic event
+ fireLabelEvent(new LabelProviderChangedEvent(this));
+ }
+ }
+
+ private void fireLabelEvent(final LabelProviderChangedEvent event) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
fireLabelProviderChanged(event);