[file-history] do not rebuild the whole visible graph after refine

This commit is contained in:
Julia Beliaeva
2018-06-14 03:44:32 +03:00
parent 9f79852160
commit ea52e844a6
8 changed files with 95 additions and 28 deletions
@@ -15,6 +15,7 @@
*/
package com.intellij.vcs.log.graph.impl.facade;
import com.intellij.util.Function;
import com.intellij.vcs.log.graph.api.elements.GraphElement;
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo;
import com.intellij.vcs.log.graph.impl.print.elements.PrintElementWithGraphElement;
@@ -44,6 +45,20 @@ public abstract class CascadeController implements LinearGraphController {
return LinearGraphUtils.DEFAULT_GRAPH_ANSWER;
}
@Nullable
GraphChanges<Integer> performAction(@NotNull Function<CascadeController, GraphChanges<Integer>> action) {
GraphChanges<Integer> graphChanges = action.fun(this);
if (graphChanges != null) return graphChanges;
if (myDelegateController instanceof CascadeController) {
GraphChanges<Integer> result = ((CascadeController)myDelegateController).performAction(action);
if (result != null) {
return delegateGraphChanged(new LinearGraphController.LinearGraphAnswer(result)).getGraphChanges();
}
}
return null;
}
@Nullable
private PrintElementWithGraphElement convertToDelegate(@Nullable PrintElementWithGraphElement element) {
if (element == null) return null;
@@ -75,4 +75,9 @@ public class FilteredController extends CascadeController {
public LinearGraph getCompiledGraph() {
return myCollapsedGraph.getCompiledGraph();
}
@NotNull
public CollapsedGraph getCollapsedGraph() {
return myCollapsedGraph;
}
}
@@ -0,0 +1,24 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.graph.impl.facade
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo
import com.intellij.vcs.log.graph.collapsing.DottedFilterEdgesGenerator
fun <CommitId> hideInplace(graphController: LinearGraphController,
permanentGraphInfo: PermanentGraphInfo<CommitId>,
toHide: Set<CommitId>): Boolean {
if (graphController is CascadeController) {
val result = graphController.performAction action@{ cc ->
if (cc is FilteredController) {
val rowsToHide = permanentGraphInfo.permanentCommitsInfo.convertToNodeIds(toHide).mapNotNullTo(mutableSetOf()) {
cc.compiledGraph.getNodeIndex(it)
}
DottedFilterEdgesGenerator.hideInplace(cc.collapsedGraph, rowsToHide)
return@action GraphChangesUtil.SOME_CHANGES
}
return@action null
}
return result != null
}
return false
}
@@ -39,6 +39,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class PermanentGraphImpl<CommitId> implements PermanentGraph<CommitId>, PermanentGraphInfo<CommitId> {
@NotNull private final PermanentCommitsInfoImpl<CommitId> myPermanentCommitsInfo;
@@ -133,13 +134,23 @@ public class PermanentGraphImpl<CommitId> implements PermanentGraph<CommitId>, P
return new CollapsedController(baseController, this, null);
}
@NotNull
public VisibleGraph<CommitId> createVisibleGraph(@NotNull SortType sortType,
@Nullable Set<CommitId> visibleHeads,
@Nullable Set<CommitId> matchingCommits,
@NotNull BiConsumer<LinearGraphController, PermanentGraphInfo<CommitId>> preprocessor) {
LinearGraphController controller = createFilteredController(createBaseController(sortType), sortType, visibleHeads, matchingCommits);
preprocessor.accept(controller, this);
return new VisibleGraphImpl<>(controller, this, myGraphColorManager);
}
@NotNull
@Override
public VisibleGraph<CommitId> createVisibleGraph(@NotNull SortType sortType,
@Nullable Set<CommitId> visibleHeads,
@Nullable Set<CommitId> matchingCommits) {
LinearGraphController controller = createFilteredController(createBaseController(sortType), sortType, visibleHeads, matchingCommits);
return new VisibleGraphImpl<>(controller, this, myGraphColorManager);
return createVisibleGraph(sortType, visibleHeads, matchingCommits, (controller, info) -> {
});
}
@NotNull
@@ -86,7 +86,12 @@ public class VisibleGraphImpl<CommitId> implements VisibleGraph<CommitId> {
return new ActionControllerImpl();
}
private void updatePrintElementGenerator() {
@NotNull
public LinearGraphController getGraphController() {
return myGraphController;
}
void updatePrintElementGenerator() {
myPrintElementManager = new PrintElementManagerImpl(myGraphController.getCompiledGraph(), myPermanentGraph, myColorManager);
myPrintElementGenerator = new PrintElementGeneratorImpl(myGraphController.getCompiledGraph(), myPrintElementManager, myShowLongEdges);
}
@@ -54,7 +54,7 @@ internal class FileHistoryRefiner(private val visibleLinearGraph: LinearGraph,
private val paths = Stack<FilePath>()
private val visibilityBuffer = BitSetFlags(permanentLinearGraph.nodesCount()) // a reusable buffer for bfs
val pathsForCommits = ContainerUtil.newHashMap<Int, FilePath>()
private val excluded = ContainerUtil.newHashSet<Int>()
val excluded = ContainerUtil.newHashSet<Int>()
fun refine(row: Int, startPath: FilePath): Boolean {
if (namesData.hasRenames) {
@@ -33,8 +33,9 @@ import com.intellij.vcs.log.graph.GraphCommitImpl
import com.intellij.vcs.log.graph.PermanentGraph
import com.intellij.vcs.log.graph.VisibleGraph
import com.intellij.vcs.log.graph.api.LiteLinearGraph
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo
import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl
import com.intellij.vcs.log.graph.impl.facade.VisibleGraphImpl
import com.intellij.vcs.log.graph.impl.facade.hideInplace
import com.intellij.vcs.log.graph.utils.LinearGraphUtils
import com.intellij.vcs.log.impl.HashImpl
import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl
@@ -44,6 +45,7 @@ import com.intellij.vcs.log.util.VcsLogUtil
import com.intellij.vcs.log.visible.CommitCountStage
import com.intellij.vcs.log.visible.VcsLogFilterer
import com.intellij.vcs.log.visible.VcsLogFiltererImpl
import com.intellij.vcs.log.visible.VcsLogFiltererImpl.matchesNothing
import com.intellij.vcs.log.visible.VisiblePack
import com.intellij.vcsUtil.VcsUtil
@@ -171,31 +173,36 @@ internal class FileHistoryFilterer(logData: VcsLogData) : VcsLogFilterer {
filters: VcsLogFilterCollection): VisiblePack {
val matchingHeads = vcsLogFilterer.getMatchingHeads(dataPack.refsModel, setOf(root), filters)
val data = indexDataGetter.buildFileNamesData(filePath)
var visibleGraph = vcsLogFilterer.createVisibleGraph(dataPack, sortType, matchingHeads, data.commits)
var pathsMap: Map<Int, FilePath>? = null
if (visibleGraph.visibleCommitCount > 0) {
if (visibleGraph is VisibleGraphImpl<*>) {
val visibleLinearGraph = (visibleGraph as VisibleGraphImpl<Int>).linearGraph
val permanentGraphInfo: PermanentGraphInfo<Int> = visibleGraph.permanentGraph
val hash = hash ?: getHead(dataPack)
val row = hash?.let {
findAncestorRowAffectingFile(storage.getCommitIndex(it, root), filePath, visibleLinearGraph, permanentGraphInfo, data)
} ?: 0
if (row >= 0) {
val refiner = FileHistoryRefiner(visibleLinearGraph, permanentGraphInfo, data)
if (refiner.refine(row, filePath)) {
// creating a vg is the most expensive task, so trying to avoid that when unnecessary
visibleGraph = vcsLogFilterer.createVisibleGraph(dataPack, sortType, matchingHeads, refiner.pathsForCommits.keys)
pathsMap = refiner.pathsForCommits
}
}
}
val permanentGraph = dataPack.permanentGraph
if (permanentGraph !is PermanentGraphImpl) {
val visibleGraph = vcsLogFilterer.createVisibleGraph(dataPack, sortType, matchingHeads, data.commits)
return FileHistoryVisiblePack(dataPack, visibleGraph, false, filters, data.buildPathsMap())
}
if (pathsMap == null) {
pathsMap = data.buildPathsMap()
if (matchesNothing(matchingHeads) || matchesNothing(data.commits)) {
return VisiblePack.EMPTY
}
val pathsMap = mutableMapOf<Int, FilePath>()
val visibleGraph = permanentGraph.createVisibleGraph(sortType, matchingHeads,
data.commits) preprocess@{ controller, permanentGraphInfo ->
val visibleLinearGraph = controller.compiledGraph
val hash = hash ?: getHead(dataPack)
val row = hash?.let {
findAncestorRowAffectingFile(storage.getCommitIndex(it, root), filePath, visibleLinearGraph, permanentGraphInfo, data)
} ?: 0
if (row >= 0) {
val refiner = FileHistoryRefiner(visibleLinearGraph, permanentGraphInfo, data)
if (refiner.refine(row, filePath)) {
// creating a vg is the most expensive task, so trying to avoid that when unnecessary
val hidden = hideInplace(controller, permanentGraphInfo, refiner.excluded)
if (!hidden) LOG.error("Could not hide excluded commits from history for " + filePath.path)
pathsMap.putAll(refiner.pathsForCommits)
return@preprocess
}
}
pathsMap.putAll(data.buildPathsMap())
}
if (!filePath.isDirectory) reindexFirstCommitsIfNeeded(visibleGraph)
@@ -164,7 +164,7 @@ public class VcsLogFiltererImpl implements VcsLogFilterer {
return false;
}
private static <T> boolean matchesNothing(@Nullable Collection<T> matchingSet) {
public static <T> boolean matchesNothing(@Nullable Collection<T> matchingSet) {
return matchingSet != null && matchingSet.isEmpty();
}