diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/ReachableNodes.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/ReachableNodes.java index 49cd9dbd90a4..435d8a7ae5e2 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/ReachableNodes.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/ReachableNodes.java @@ -31,6 +31,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.function.IntPredicate; public class ReachableNodes { @NotNull private final LiteLinearGraph myGraph; @@ -72,6 +73,13 @@ public class ReachableNodes { } private void walk(@NotNull Collection startNodes, boolean goDown, @NotNull Consumer consumer) { + walk(startNodes, goDown, node -> { + consumer.consume(node); + return true; + }); + } + + public void walk(@NotNull Collection startNodes, boolean goDown, @NotNull IntPredicate consumer) { synchronized (myTempFlags) { myTempFlags.setAll(false); @@ -79,16 +87,16 @@ public class ReachableNodes { if (start < 0) continue; if (myTempFlags.get(start)) continue; myTempFlags.set(start, true); - consumer.consume(start); + if (!consumer.test(start)) return; - DfsUtil.walk(start, currentNode -> { - for (int downNode : myGraph.getNodes(currentNode, goDown ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) { - if (!myTempFlags.get(downNode)) { - myTempFlags.set(downNode, true); - consumer.consume(downNode); - return downNode; + DfsUtil.walk(start, currentNode-> { + for (int downNode : myGraph.getNodes(currentNode, goDown ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) { + if (!myTempFlags.get(downNode)) { + myTempFlags.set(downNode, true); + if (!consumer.test(downNode)) return DfsUtil.NextNode.EXIT; + return downNode; + } } - } return DfsUtil.NextNode.NODE_NOT_FOUND; }); diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java index e88bde7eedbe..b1704cf4c067 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java @@ -19,6 +19,7 @@ import com.intellij.vcs.log.graph.*; import com.intellij.vcs.log.graph.actions.ActionController; import com.intellij.vcs.log.graph.actions.GraphAction; import com.intellij.vcs.log.graph.actions.GraphAnswer; +import com.intellij.vcs.log.graph.api.LinearGraph; import com.intellij.vcs.log.graph.api.elements.GraphEdge; import com.intellij.vcs.log.graph.api.elements.GraphEdgeType; import com.intellij.vcs.log.graph.api.elements.GraphElement; @@ -97,6 +98,10 @@ public class VisibleGraphImpl implements VisibleGraph { return myPrintElementGenerator.getRecommendedWidth(); } + public LinearGraph getLinearGraph() { + return myGraphController.getCompiledGraph(); + } + private class ActionControllerImpl implements ActionController { @Nullable diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/utils/DfsUtil.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/utils/DfsUtil.java index 38590d844979..c6717ad747d4 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/utils/DfsUtil.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/utils/DfsUtil.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; public class DfsUtil { public interface NextNode { int NODE_NOT_FOUND = -1; + int EXIT = -10; int fun(int currentNode); } @@ -32,6 +33,7 @@ public class DfsUtil { while (!stack.empty()) { int nextNode = nextNodeFun.fun(stack.peek()); + if (nextNode == NextNode.EXIT) return; if (nextNode != NextNode.NODE_NOT_FOUND) { stack.push(nextNode); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CompressedRefs.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CompressedRefs.java index 4125823da89c..7e518c85ae9e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CompressedRefs.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CompressedRefs.java @@ -77,7 +77,7 @@ public class CompressedRefs { } @NotNull - Stream streamBranches() { + public Stream streamBranches() { return TroveUtil.streamValues(myBranches).flatMap(Collection::stream); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/IndexDataGetter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/IndexDataGetter.java index 373e8855ad80..848d83982a8c 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/IndexDataGetter.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/IndexDataGetter.java @@ -16,11 +16,15 @@ package com.intellij.vcs.log.data.index; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.UnorderedPair; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.StorageException; import com.intellij.vcs.log.impl.FatalErrorHandler; import com.intellij.vcsUtil.VcsUtil; +import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -69,4 +73,103 @@ public class IndexDataGetter { return Collections.emptySet(); } + + @NotNull + public FileNamesData buildFileNamesData(@NotNull FilePath path) { + FileNamesData result = new FileNamesData(); + + VirtualFile root = VcsUtil.getVcsRootFor(myProject, path); + if (myRoots.contains(root)) { + try { + myIndexStorage.paths.iterateCommits(Collections.singleton(path), (paths, commit) -> result.add(commit, paths)); + } + catch (IOException | StorageException e) { + myFatalErrorsConsumer.consume(this, e); + } + } + + return result; + } + + public static class FileNamesData { + @NotNull private final TIntObjectHashMap> myCommitsToPaths; + @NotNull private final TIntObjectHashMap>> myCommitsToRenames; + + public FileNamesData() { + myCommitsToPaths = new TIntObjectHashMap<>(); + myCommitsToRenames = new TIntObjectHashMap<>(); + } + + public boolean hasRenames() { + return !myCommitsToRenames.isEmpty(); + } + + private void addPath(int commit, @NotNull FilePath path) { + Set paths = myCommitsToPaths.get(commit); + if (paths == null) { + paths = ContainerUtil.newHashSet(); + myCommitsToPaths.put(commit, paths); + } + paths.add(path); + } + + private void addRename(int commit, @NotNull Couple path) { + Set> paths = myCommitsToRenames.get(commit); + if (paths == null) { + paths = ContainerUtil.newHashSet(); + myCommitsToRenames.put(commit, paths); + } + paths.add(new UnorderedPair<>(path.first, path.second)); + } + + public void add(int commit, @NotNull Couple paths) { + if (paths.second == null) { + addPath(commit, paths.first); + } + else { + addRename(commit, paths); + } + } + + public boolean affects(int commit, @NotNull FilePath path) { + Set paths = myCommitsToPaths.get(commit); + if (paths != null && paths.contains(path)) return true; + return getRenamedPath(commit, path) != null; + } + + @Nullable + public FilePath getRenamedPath(int commit, @Nullable FilePath newName) { + Set> renames = myCommitsToRenames.get(commit); + if (renames == null) return null; + + for (UnorderedPair rename : renames) { + if (rename.first.equals(newName)) return rename.second; + if (rename.second.equals(newName)) return rename.first; + } + return null; + } + + @Nullable + public FilePath getPreviousPath(int commit, @Nullable FilePath path) { + Set paths = myCommitsToPaths.get(commit); + if (paths != null && paths.contains(path)) return path; + return getRenamedPath(commit, path); + } + + public void remove(int commit) { + myCommitsToPaths.remove(commit); + myCommitsToRenames.remove(commit); + } + + public void retain(int commit, @NotNull FilePath path, @NotNull FilePath previousPath) { + if (path.equals(previousPath)) { + myCommitsToPaths.put(commit, ContainerUtil.set(path)); + myCommitsToRenames.remove(commit); + } + else { + myCommitsToPaths.remove(commit); + myCommitsToRenames.put(commit, ContainerUtil.set(new UnorderedPair<>(path, previousPath))); + } + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java index 340614aa4660..15b73bdea0ed 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java @@ -46,6 +46,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Map; import java.util.Set; +import java.util.function.ObjIntConsumer; import static com.intellij.util.containers.ContainerUtil.newTroveSet; import static com.intellij.vcs.log.data.index.VcsLogPersistentIndex.getVersion; @@ -82,11 +83,9 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { myPathsIndexer.getPathsEnumerator().force(); } + @NotNull public TIntHashSet getCommitsForPaths(@NotNull Collection paths) throws IOException, StorageException { - Set allPathIds = ContainerUtil.newHashSet(); - for (FilePath path : paths) { - allPathIds.add(myPathsIndexer.myPathsEnumerator.enumerate(path.getPath())); - } + Set allPathIds = getPathIds(paths); TIntHashSet result = new TIntHashSet(); Set renames = allPathIds; @@ -98,6 +97,15 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { return result; } + @NotNull + private Set getPathIds(@NotNull Collection paths) throws IOException { + Set allPathIds = ContainerUtil.newHashSet(); + for (FilePath path : paths) { + allPathIds.add(myPathsIndexer.myPathsEnumerator.enumerate(path.getPath())); + } + return allPathIds; + } + @NotNull public Set getFileNames(@NotNull FilePath path, int commit) throws IOException, StorageException { int startId = myPathsIndexer.myPathsEnumerator.enumerate(path.getPath()); @@ -138,6 +146,37 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { return result; } + public void iterateCommits(@NotNull Collection paths, @NotNull ObjIntConsumer> consumer) + throws IOException, StorageException { + + Set startIds = getPathIds(paths); + Set allIds = ContainerUtil.newHashSet(startIds); + Set newIds = ContainerUtil.newHashSet(); + while (!startIds.isEmpty()) { + for (int currentPathId : startIds) { + FilePath currentPath = VcsUtil.getFilePath(myPathsIndexer.myPathsEnumerator.valueOf(currentPathId)); + iterateCommitIdsAndValues(currentPathId, (renamedPathId, commitId) -> { + FilePath renamedPath = null; + if (renamedPathId != null) { + if (!allIds.contains(renamedPathId)) { + newIds.add(renamedPathId); + } + try { + renamedPath = VcsUtil.getFilePath(myPathsIndexer.myPathsEnumerator.valueOf(renamedPathId)); + } + catch (IOException e) { + LOG.error(e); + } + } + consumer.accept(Couple.of(currentPath, renamedPath), commitId); + }); + } + startIds = ContainerUtil.newHashSet(newIds); + allIds.addAll(startIds); + newIds.clear(); + } + } + @NotNull public Set addCommitsAndGetRenames(@NotNull Set newPathIds, @NotNull Set allPathIds, diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/history/FileHistoryFilterer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/history/FileHistoryFilterer.java index 473334f657ca..1311227e0470 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/history/FileHistoryFilterer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/history/FileHistoryFilterer.java @@ -15,20 +15,228 @@ */ package com.intellij.vcs.log.ui.history; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Stack; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsLogFilterCollection; +import com.intellij.vcs.log.VcsRef; +import com.intellij.vcs.log.data.CompressedRefs; +import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogData; +import com.intellij.vcs.log.data.index.IndexDataGetter; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.graph.VisibleGraph; +import com.intellij.vcs.log.graph.api.LinearGraph; +import com.intellij.vcs.log.graph.api.LiteLinearGraph; +import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl; +import com.intellij.vcs.log.graph.impl.facade.ReachableNodes; +import com.intellij.vcs.log.graph.impl.facade.VisibleGraphImpl; +import com.intellij.vcs.log.graph.impl.permanent.PermanentCommitsInfoImpl; +import com.intellij.vcs.log.graph.utils.LinearGraphUtils; +import com.intellij.vcs.log.graph.utils.impl.BitSetFlags; import com.intellij.vcs.log.visible.VcsLogFilterer; +import com.intellij.vcs.log.visible.VisiblePack; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; class FileHistoryFilterer extends VcsLogFilterer { @NotNull private final FilePath myFilePath; + @NotNull private final IndexDataGetter myIndexDataGetter; + @NotNull private final VirtualFile myRoot; public FileHistoryFilterer(@NotNull VcsLogData logData, @NotNull FilePath filePath) { super(logData.getLogProviders(), logData.getStorage(), logData.getTopCommitsCache(), logData.getCommitDetailsGetter(), logData.getIndex()); myFilePath = filePath; + myIndexDataGetter = ObjectUtils.assertNotNull(myIndex.getDataGetter()); + myRoot = ObjectUtils.assertNotNull(VcsUtil.getVcsRootFor(logData.getProject(), myFilePath)); } - // this is empty now - // that's going to change soon + @NotNull + protected VisiblePack createVisiblePack(@NotNull DataPack dataPack, + @NotNull PermanentGraph.SortType sortType, + @NotNull VcsLogFilterCollection filters, + @Nullable Set matchingHeads, + @Nullable Set matchingCommits, + boolean canRequestMore) { + if (!myIndex.isIndexed(myRoot) || matchingCommits == null) { + return super.createVisiblePack(dataPack, sortType, filters, matchingHeads, matchingCommits, canRequestMore); + } + // I realize, I'm calculating this data for the second time. + // No worries! It's going to be fine later! + IndexDataGetter.FileNamesData namesData = myIndexDataGetter.buildFileNamesData(myFilePath); + if (!namesData.hasRenames()) { + return super.createVisiblePack(dataPack, sortType, filters, matchingHeads, matchingCommits, canRequestMore); + } + + VisibleGraph visibleGraph = createVisibleGraph(dataPack, sortType, matchingHeads, matchingCommits); + if (visibleGraph instanceof VisibleGraphImpl) { + FileHistoryRefiner refiner = new FileHistoryRefiner(visibleGraph, namesData); + if (refiner.refine(((VisibleGraphImpl)visibleGraph).getLinearGraph(), getCurrentRow(dataPack, visibleGraph, namesData), myFilePath)) { + // creating a vg is the most expensive task, so trying to avoid that when unnecessary + return new VisiblePack(dataPack, createVisibleGraph(dataPack, sortType, matchingHeads, refiner.getMatchingCommits()), + canRequestMore, + filters); + } + } + + return new VisiblePack(dataPack, visibleGraph, canRequestMore, filters); + } + + private int getCurrentRow(@NotNull DataPack pack, + @NotNull VisibleGraph visibleGraph, + @NotNull IndexDataGetter.FileNamesData fileIndexData) { + PermanentGraph permanentGraph = pack.getPermanentGraph(); + if (permanentGraph instanceof PermanentGraphImpl) { + CompressedRefs refs = pack.getRefsModel().getAllRefsByRoot().get(myRoot); + Optional headOptional = refs.streamBranches().filter(br -> br.getName().equals("HEAD")).findFirst(); + if (headOptional.isPresent()) { + VcsRef head = headOptional.get(); + assert head.getRoot().equals(myRoot); + return findAncestorRowAffectingFile((PermanentGraphImpl)permanentGraph, head.getCommitHash(), visibleGraph, fileIndexData); + } + } + return 0; + } + + private int findAncestorRowAffectingFile(@NotNull PermanentGraphImpl permanentGraph, + @NotNull Hash hash, + @NotNull VisibleGraph visibleGraph, + @NotNull IndexDataGetter.FileNamesData fileNamesData) { + Ref result = new Ref<>(); + + PermanentCommitsInfoImpl commitsInfo = permanentGraph.getPermanentCommitsInfo(); + ReachableNodes reachableNodes = new ReachableNodes(LinearGraphUtils.asLiteLinearGraph(permanentGraph.getLinearGraph())); + reachableNodes.walk(Collections.singleton(commitsInfo.getNodeId(myStorage.getCommitIndex(hash, myRoot))), true, + currentNode -> { + int id = commitsInfo.getCommitId(currentNode); + if (fileNamesData.affects(id, myFilePath)) { + result.set(currentNode); + return false; // stop walk, we have found it + } + return true; // continue walk + }); + + if (!result.isNull()) { + Integer rowIndex = visibleGraph.getVisibleRowIndex(commitsInfo.getCommitId(result.get())); + return ObjectUtils.assertNotNull(rowIndex); + } + + return 0; + } + + private static void walk(@NotNull LiteLinearGraph graph, int start, @NotNull NodeVisitor visitor) { + BitSetFlags visited = new BitSetFlags(graph.nodesCount(), false); + BitSetFlags visitedInSameDirection = new BitSetFlags(graph.nodesCount(), false); + + Stack> stack = new Stack<>(); + stack.push(new Pair<>(start, true)); // commit + direction of travel + + while (!stack.empty()) { + int currentNode = stack.peek().first; + boolean down = stack.peek().second; + if (!visited.get(currentNode)) { + visited.set(currentNode, true); + visitor.enterNode(currentNode); + } + + boolean found = false; + for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) { + if (!visited.get(nextNode)) { + stack.push(new Pair<>(nextNode, down)); + found = true; + break; + } + } + + if (!found) { + if (!visitedInSameDirection.get(currentNode)) { + visitedInSameDirection.set(currentNode, true); + visitor.exitNode(currentNode); + } + for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.UP : LiteLinearGraph.NodeFilter.DOWN)) { + if (!visited.get(nextNode)) { + stack.push(new Pair<>(nextNode, !down)); + found = true; + break; + } + } + } + + if (!found) { + stack.pop(); + } + } + } + + public interface NodeVisitor { + void enterNode(int node); + + void exitNode(int node); + } + + private static class FileHistoryRefiner implements NodeVisitor { + @NotNull private final VisibleGraph myVisibleGraph; + @NotNull private final IndexDataGetter.FileNamesData myNamesData; + @NotNull private final Stack myPaths; + @NotNull private final Set myMatchingCommits; + + private boolean myWasChanged; + + public FileHistoryRefiner(@NotNull VisibleGraph visibleGraph, + @NotNull IndexDataGetter.FileNamesData namesData) { + myVisibleGraph = visibleGraph; + myNamesData = namesData; + + myPaths = new Stack<>(); + myMatchingCommits = ContainerUtil.newHashSet(); + myWasChanged = false; + } + + public boolean refine(@NotNull LinearGraph graph, int row, @NotNull FilePath startPath) { + myPaths.push(startPath); + walk(LinearGraphUtils.asLiteLinearGraph(graph), row, this); + return myWasChanged; + } + + @NotNull + public Set getMatchingCommits() { + return myMatchingCommits; + } + + @Override + public void enterNode(int node) { + FilePath currentPath = myPaths.peek(); + Integer commit = myVisibleGraph.getRowInfo(node).getCommit(); + + FilePath previousPath = myNamesData.getPreviousPath(commit, currentPath); + if (previousPath != null) { + myMatchingCommits.add(commit); + if (!currentPath.equals(previousPath)) myPaths.push(previousPath); + myNamesData.retain(commit, currentPath, previousPath); + } + else { + myNamesData.remove(commit); + myWasChanged = true; + } + } + + @Override + public void exitNode(int node) { + Integer commit = myVisibleGraph.getRowInfo(node).getCommit(); + if (myMatchingCommits.contains(commit)) { + if (myNamesData.getRenamedPath(commit, myPaths.peek()) != null) myPaths.pop(); + } + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VcsLogFilterer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VcsLogFilterer.java index c01aa35f7fbf..5e777d5b09a3 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VcsLogFilterer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VcsLogFilterer.java @@ -42,11 +42,11 @@ public class VcsLogFilterer { private static final Logger LOG = Logger.getInstance(VcsLogFilterer.class); - @NotNull private final VcsLogStorage myStorage; + @NotNull protected final VcsLogStorage myStorage; @NotNull private final TopCommitsCache myTopCommitsDetailsCache; @NotNull private final DataGetter myCommitDetailsGetter; @NotNull private final Map myLogProviders; - @NotNull private final VcsLogIndex myIndex; + @NotNull protected final VcsLogIndex myIndex; public VcsLogFilterer(@NotNull Map providers, @NotNull VcsLogStorage storage, @@ -77,17 +77,37 @@ public class VcsLogFilterer { Set matchingHeads = getMatchingHeads(dataPack.getRefsModel(), visibleRoots, filters); FilterResult filterResult = filterByDetails(dataPack, filters, commitCount, visibleRoots, matchingHeads); + VisiblePack visiblePack = + createVisiblePack(dataPack, sortType, filters, matchingHeads, filterResult.matchingCommits, filterResult.canRequestMore); + + LOG.debug(StopWatch.formatTime(System.currentTimeMillis() - start) + " for filtering by " + filters); + return Pair.create(visiblePack, filterResult.commitCount); + } + + @NotNull + protected VisiblePack createVisiblePack(@NotNull DataPack dataPack, + @NotNull PermanentGraph.SortType sortType, + @NotNull VcsLogFilterCollection filters, + @Nullable Set matchingHeads, + @Nullable Set matchingCommits, + boolean canRequestMore) { + VisibleGraph visibleGraph = createVisibleGraph(dataPack, sortType, matchingHeads, matchingCommits); + return new VisiblePack(dataPack, visibleGraph, canRequestMore, filters); + } + + @NotNull + protected VisibleGraph createVisibleGraph(@NotNull DataPack dataPack, + @NotNull PermanentGraph.SortType sortType, + @Nullable Set matchingHeads, + @Nullable Set matchingCommits) { VisibleGraph visibleGraph; - if (matchesNothing(matchingHeads) || matchesNothing(filterResult.matchingCommits)) { + if (matchesNothing(matchingHeads) || matchesNothing(matchingCommits)) { visibleGraph = EmptyVisibleGraph.getInstance(); } else { - visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, matchingHeads, filterResult.matchingCommits); + visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, matchingHeads, matchingCommits); } - - LOG.debug(StopWatch.formatTime(System.currentTimeMillis() - start) + " for filtering by " + filters); - - return Pair.create(new VisiblePack(dataPack, visibleGraph, filterResult.canRequestMore, filters), filterResult.commitCount); + return visibleGraph; } @NotNull diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VisiblePack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VisiblePack.java index 0c4835d92526..2c9a3e462b20 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VisiblePack.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/visible/VisiblePack.java @@ -38,10 +38,10 @@ public class VisiblePack implements VcsLogDataPack { private final boolean myCanRequestMore; @NotNull private final VcsLogFilterCollection myFilters; - VisiblePack(@NotNull DataPackBase dataPack, - @NotNull VisibleGraph graph, - boolean canRequestMore, - @NotNull VcsLogFilterCollection filters) { + public VisiblePack(@NotNull DataPackBase dataPack, + @NotNull VisibleGraph graph, + boolean canRequestMore, + @NotNull VcsLogFilterCollection filters) { myDataPack = dataPack; myVisibleGraph = graph; myCanRequestMore = canRequestMore;