diff options
author | Markus Duft | 2012-11-07 07:34:55 +0000 |
---|---|---|
committer | Matthias Sohn | 2012-12-02 00:26:18 +0000 |
commit | 78a566bf0c192c4cb71ec0ff12369410375018d8 (patch) | |
tree | 9e8846439e929a0aba271a4a9ba40845d9950cba | |
parent | 50805925cbaeb3a81223d378f26aac8333ae6258 (diff) | |
download | egit-78a566bf0c192c4cb71ec0ff12369410375018d8.tar.gz egit-78a566bf0c192c4cb71ec0ff12369410375018d8.tar.xz egit-78a566bf0c192c4cb71ec0ff12369410375018d8.zip |
Refresh only deltas to the last refresh in IndexDiffCacheEntry
This change is a EGit-only implementation of the preceding changes:
EGit: Change-Id: I5cd27f79606decca73b7a0977d147c97e06bfaba
JGit: Change-Id: Ia1eae05793483a3fc837e4e0d28c2a52c5013d0b
This has the advantage over the other implementation that it is local to
the location that actually has the performance issue.
Bug: 393642
Change-Id: I5cd27f79606decca73b7a0977d147c97e06bfaba
Also-by: Robin Stocker <robin@nibor.org>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 files changed, 123 insertions, 8 deletions
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/indexDiff/IndexDiffCacheTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/indexDiff/IndexDiffCacheTest.java index a191efcae2..3922654fd2 100644 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/indexDiff/IndexDiffCacheTest.java +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/indexDiff/IndexDiffCacheTest.java @@ -27,7 +27,6 @@ import org.eclipse.egit.core.op.ConnectProviderOperation; import org.eclipse.egit.core.test.GitTestCase; import org.eclipse.egit.core.test.TestRepository; import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.events.IndexChangedEvent; import org.eclipse.jgit.lib.Repository; import org.junit.After; import org.junit.Before; @@ -75,9 +74,8 @@ public class IndexDiffCacheTest extends GitTestCase { .toString().substring(1); if (!indexDiffData.getUntracked().contains(path)) fail("IndexDiffData did not contain aFile as untracked"); - new Git(repository).add().addFilepattern(path).call(); // This call should trigger an indexDiffChanged event - repository.fireEvent(new IndexChangedEvent()); + new Git(repository).add().addFilepattern(path).call(); IndexDiffData indexDiffData2 = waitForListenerCalled(); if (indexDiffData2.getUntracked().contains(path)) fail("IndexDiffData contains aFile as untracked"); diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java index c9c6c05720..7e9a1b04a0 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java @@ -2,6 +2,7 @@ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2012, Robin Stocker <robin@nibor.org> + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -262,6 +263,9 @@ public class CoreText extends NLS { public static String CreatePatchOperation_patchFileCouldNotBeWritten; /** */ + public static String IndexDiffCacheEntry_errorCalculatingIndexDelta; + + /** */ public static String IndexDiffCacheEntry_refreshingProjects; /** */ diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties index f478b17ece..846681da0a 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties @@ -105,6 +105,7 @@ CreatePatchOperation_cannotCreatePatchForMergeCommit=Cannot create patch for mer CreatePatchOperation_cannotCreatePatchForFirstCommit=Cannot create patch for first commit CreatePatchOperation_couldNotFindProject=Could not find project for {0} in repository {1} CreatePatchOperation_patchFileCouldNotBeWritten=Patch file could not be written +IndexDiffCacheEntry_errorCalculatingIndexDelta=Failed to load index for repository {0} IndexDiffCacheEntry_refreshingProjects=Refreshing projects of repository {0} IndexDiffCacheEntry_reindexing=Re-indexing repository {0} IndexFileRevision_errorLookingUpPath=IO error looking up path {0} in index. diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffCacheEntry.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffCacheEntry.java index 6493d5a0d7..52c078cb05 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffCacheEntry.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffCacheEntry.java @@ -1,5 +1,7 @@ /******************************************************************************* * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> + * Copyright (C) 2012, Robin Stocker <robin@nibor.org> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -10,11 +12,13 @@ package org.eclipse.egit.core.internal.indexdiff; import java.io.IOException; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.core.resources.IProject; @@ -36,6 +40,8 @@ import org.eclipse.egit.core.IteratorService; import org.eclipse.egit.core.JobFamilies; import org.eclipse.egit.core.internal.trace.GitTraceLocation; import org.eclipse.egit.core.internal.util.ProjectUtil; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.events.IndexChangedEvent; import org.eclipse.jgit.events.IndexChangedListener; import org.eclipse.jgit.events.RefsChangedEvent; @@ -43,8 +49,10 @@ import org.eclipse.jgit.events.RefsChangedListener; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.IndexDiff; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.osgi.util.NLS; /** @@ -63,6 +71,8 @@ public class IndexDiffCacheEntry { private Job reloadJob; + private DirCache lastIndex; + // used to serialize index diff update jobs private ReentrantLock lock = new ReentrantLock(true); @@ -78,7 +88,7 @@ public class IndexDiffCacheEntry { repository.getListenerList().addIndexChangedListener( new IndexChangedListener() { public void onIndexChanged(IndexChangedEvent event) { - scheduleReloadJob("IndexChanged"); //$NON-NLS-1$ + refreshIndexDelta(); } }); repository.getListenerList().addRefsChangedListener( @@ -89,6 +99,16 @@ public class IndexDiffCacheEntry { }); scheduleReloadJob("IndexDiffCacheEntry construction"); //$NON-NLS-1$ createResourceChangeListener(); + if (!repository.isBare()) { + try { + lastIndex = repository.readDirCache(); + } catch (IOException ex) { + Activator + .error(MessageFormat + .format(CoreText.IndexDiffCacheEntry_errorCalculatingIndexDelta, + repository), ex); + } + } } /** @@ -163,6 +183,57 @@ public class IndexDiffCacheEntry { } /** + * Refreshes all resources that changed in the index since the last call to + * this method. This is suitable for incremental updates on index changed + * events + * + * For bare repositories this does nothing. + */ + private void refreshIndexDelta() { + if (repository.isBare()) + return; + + try { + DirCache currentIndex = repository.readDirCache(); + DirCache oldIndex = lastIndex; + + lastIndex = currentIndex; + + if (oldIndex == null) { + refresh(); // full refresh in case we have no data to compare. + return; + } + + Set<String> paths = new TreeSet<String>(); + TreeWalk walk = new TreeWalk(repository); + + try { + walk.addTree(new DirCacheIterator(oldIndex)); + walk.addTree(new DirCacheIterator(currentIndex)); + walk.setFilter(TreeFilter.ANY_DIFF); + + while (walk.next()) { + if (walk.isSubtree()) + walk.enterSubtree(); + else + paths.add(walk.getPathString()); + } + } finally { + walk.release(); + } + + if (!paths.isEmpty()) + refreshFiles(paths); + + } catch (IOException ex) { + Activator.error(MessageFormat.format( + CoreText.IndexDiffCacheEntry_errorCalculatingIndexDelta, + repository), ex); + scheduleReloadJob("Exception while calculating index delta, doing full reload instead"); //$NON-NLS-1$ + } + } + + /** * The method returns the current index diff or null. Null is returned if * the first index diff calculation has not completed yet. * @@ -313,17 +384,36 @@ public class IndexDiffCacheEntry { EclipseGitProgressTransformer jgitMonitor = new EclipseGitProgressTransformer( monitor); + List<String> treeFilterPaths = calcTreeFilterPaths(filesToUpdate); + WorkingTreeIterator iterator = IteratorService .createInitialIterator(repository); IndexDiff diffForChangedResources = new IndexDiff(repository, Constants.HEAD, iterator); diffForChangedResources.setFilter(PathFilterGroup - .createFromStrings(filesToUpdate)); + .createFromStrings(treeFilterPaths)); diffForChangedResources.diff(jgitMonitor, 0, 0, jobName); return new IndexDiffData(indexDiffData, filesToUpdate, resourcesToUpdate, diffForChangedResources); } + /* + * In the case when a file to update was in a folder that was untracked + * before, we need to visit more that just the file. E.g. when the file is + * now tracked, the folder is no longer untracked but maybe some sub folders + * have become newly untracked. + */ + private List<String> calcTreeFilterPaths(Collection<String> filesToUpdate) { + List<String> paths = new ArrayList<String>(); + for (String fileToUpdate : filesToUpdate) { + for (String untrackedFolder : indexDiffData.getUntrackedFolders()) + if (fileToUpdate.startsWith(untrackedFolder)) + paths.add(untrackedFolder); + paths.add(fileToUpdate); + } + return paths; + } + private void notifyListeners() { IndexDiffChangedListener[] tmpListeners; synchronized (listeners) { diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffData.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffData.java index 5e04f48eca..3cb3dac2c7 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffData.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/indexdiff/IndexDiffData.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> + * Copyright (C) 2011, 2012 Jens Baumgart <jens.baumgart@sap.com> and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -99,7 +99,6 @@ public class IndexDiffData { Set<String> missing2 = new HashSet<String>(baseDiff.getMissing()); Set<String> modified2 = new HashSet<String>(baseDiff.getModified()); Set<String> untracked2 = new HashSet<String>(baseDiff.getUntracked()); - Set<String> untrackedFolders2 = new HashSet<String>(baseDiff.getUntrackedFolders()); Set<String> conflicts2 = new HashSet<String>(baseDiff.getConflicting()); Set<String> ignored2 = new HashSet<String>(baseDiff.getIgnoredNotInIndex()); @@ -109,7 +108,9 @@ public class IndexDiffData { mergeList(missing2, changedFiles, diffForChangedFiles.getMissing()); mergeList(modified2, changedFiles, diffForChangedFiles.getModified()); mergeList(untracked2, changedFiles, diffForChangedFiles.getUntracked()); - mergeList(untrackedFolders2, changedFiles, getUntrackedFolders(diffForChangedFiles)); + Set<String> untrackedFolders2 = mergeUntrackedFolders( + baseDiff.getUntrackedFolders(), changedFiles, + getUntrackedFolders(diffForChangedFiles)); mergeList(conflicts2, changedFiles, diffForChangedFiles.getConflicting()); mergeList(ignored2, changedFiles, @@ -139,6 +140,27 @@ public class IndexDiffData { } } + private static Set<String> mergeUntrackedFolders(Set<String> oldUntrackedFolders, + Collection<String> changedFiles, Set<String> newUntrackedFolders) { + Set<String> merged = new HashSet<String>(); + for (String oldUntrackedFolder : oldUntrackedFolders) { + boolean changeInUntrackedFolder = isAnyFileContainedInFolder( + oldUntrackedFolder, changedFiles); + if (!changeInUntrackedFolder) + merged.add(oldUntrackedFolder); + } + merged.addAll(newUntrackedFolders); + return merged; + } + + private static boolean isAnyFileContainedInFolder(String folder, + Collection<String> files) { + for (String file : files) + if (file.startsWith(folder)) + return true; + return false; + } + /** * @return list of files added to the index, not in the tree */ |