diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 4f29c871f8ba..0ebca68491a2 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -53,7 +53,9 @@ + text="Show History as Graph" description="Show History as Graph" internal="true"/> + @@ -74,10 +76,12 @@ + + diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogFullDetailsIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogFullDetailsIndex.java index 4ffe35533079..1ac482522e6f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogFullDetailsIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogFullDetailsIndex.java @@ -17,7 +17,6 @@ package com.intellij.vcs.log.data.index; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Pair; import com.intellij.util.Consumer; import com.intellij.util.PathUtilRt; import com.intellij.util.indexing.*; @@ -26,6 +25,7 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.util.PersistentUtil; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -149,6 +149,11 @@ public class VcsLogFullDetailsIndex implements Disposable { return new File(subdir, safeLogId + "." + version); } + @Nullable + protected Collection getKeysForCommit(int commit) throws IOException { + return myMapReduceIndex.getInputsIndex().get(commit); + } + private class MyMapReduceIndex extends MapReduceIndex { public MyMapReduceIndex(@NotNull DataIndexer indexer, @@ -160,6 +165,11 @@ public class VcsLogFullDetailsIndex implements Disposable { externalizer, 5000)); } + @NotNull + public PersistentHashMap> getInputsIndex() { + return myInputsIndex; + } + public boolean isIndexed(int commitId) throws IOException { return myInputsIndex.containsMapping(commitId); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java index 4e286fa3bfca..b96dda768209 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java @@ -31,6 +31,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.util.Collection; import java.util.Map; public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex { @@ -97,6 +98,26 @@ public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex { myNoTrigramsCommits.markCorrupted(); } + @NotNull + public String getTrigramInfo(int commit) throws IOException { + if (myNoTrigramsCommits.containsMapping(commit)) { + return "No trigrams"; + } + + Collection keys = getKeysForCommit(commit); + assert keys != null; + + StringBuilder builder = new StringBuilder(); + for (Integer key : keys) { + builder.append((char)(key >> 16)); + builder.append((char)((key >> 8) % 256)); + builder.append((char)(key % 256)); + builder.append(" "); + } + + return builder.toString(); + } + public static class TrigramMessageIndexer implements DataIndexer { @NotNull @Override 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 daf5ac4f09ac..fa4dc6b372a8 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 @@ -168,6 +168,20 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { myEmptyCommits.markCorrupted(); } + @NotNull + public String getPathInfo(int commit) throws IOException { + if (myEmptyCommits.containsMapping(commit)) { + return "No paths"; + } + Collection keys = getKeysForCommit(commit); + assert keys != null; + StringBuilder builder = new StringBuilder(); + for (int key : keys) { + builder.append(myPathsIndexer.getPathsEnumerator().valueOf(key)).append("\n"); + } + return builder.toString(); + } + private static class PathsIndexer implements DataIndexer { @NotNull private final PersistentEnumeratorBase myPathsEnumerator; @NotNull private final Set myRoots; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPersistentIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPersistentIndex.java index 80a8c762e9c1..ddebff28b9d1 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPersistentIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPersistentIndex.java @@ -374,6 +374,44 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable { } } + public void printDebugInfoForCommit(@NotNull CommitId commitId) { + int commit = myHashMap.getCommitIndex(commitId.getHash(), commitId.getRoot()); + if (!isIndexed(commit)) { + LOG.info("Commit " + commitId.getHash().asString() + " is not indexed."); + } + else { + StringBuilder builder = new StringBuilder(); + try { + builder.append("Commit ").append(commitId.getHash().asString()).append(" index info:\n"); + + builder.append("Message:\n").append(myMessagesIndex.get(commit)).append("\n"); + if (myTrigramIndex != null) { + builder.append("Trigrams:\n").append(myTrigramIndex.getTrigramInfo(commit)).append("\n"); + } + else { + builder.append("Trigrams index is null"); + } + if (myUserIndex != null) { + builder.append("User:\n").append(myUserIndex.getUserInfo(commit)).append("\n"); + } + else { + builder.append("User index is null"); + } + if (myPathsIndex != null) { + builder.append("Paths:\n").append(myPathsIndex.getPathInfo(commit)).append("\n"); + } + else { + builder.append("Paths index is null"); + } + } + catch (IOException e) { + LOG.error(e); + } + + LOG.info(builder.toString()); + } + } + private class MyIndexingTask extends Task.Backgroundable { private static final int MAGIC_NUMBER = 150000; private final Map myCommits; @@ -506,8 +544,8 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable { flush(); } - } + private static class CommitsCounter { @NotNull public final ProgressIndicator indicator; public final int allCommits; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java index f7ed31cc5cd3..5338d9a2f79d 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java @@ -18,6 +18,7 @@ package com.intellij.vcs.log.data.index; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.DataIndexer; import com.intellij.util.indexing.ScalarIndexExtension; @@ -31,6 +32,7 @@ import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.util.Collection; import java.util.Map; import java.util.Set; @@ -59,6 +61,14 @@ public class VcsLogUserIndex extends VcsLogFullDetailsIndex { return getCommitsWithAnyKey(ids); } + @NotNull + public String getUserInfo(int commit) throws IOException { + Collection keys = getKeysForCommit(commit); + assert keys != null; + assert keys.size() == 1; + return ObjectUtils.assertNotNull(myUserRegistry.getUserById(ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(keys)))).toString(); + } + private static class UserIndexer implements DataIndexer { @NotNull private final VcsUserRegistryImpl myRegistry; @NotNull private Consumer myFatalErrorConsumer = LOG::error; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/PrintIndexInfoAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/PrintIndexInfoAction.java new file mode 100644 index 000000000000..6af11fef8d8a --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/PrintIndexInfoAction.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.vcs.log.ui.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; +import com.intellij.vcs.log.CommitId; +import com.intellij.vcs.log.VcsLog; +import com.intellij.vcs.log.VcsLogDataKeys; +import com.intellij.vcs.log.data.VcsLogData; +import com.intellij.vcs.log.data.index.VcsLogIndex; +import com.intellij.vcs.log.data.index.VcsLogPersistentIndex; +import com.intellij.vcs.log.impl.VcsProjectLog; + +import java.util.List; + +public class PrintIndexInfoAction extends DumbAwareAction { + @Override + public void update(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + if (!Registry.is("vcs.log.highlight.not.indexed")) { + presentation.setEnabledAndVisible(false); + } + else { + Project project = e.getProject(); + VcsLog log = e.getData(VcsLogDataKeys.VCS_LOG); + if (project == null || log == null) { + presentation.setEnabledAndVisible(false); + } + else { + VcsLogData dataManager = VcsProjectLog.getInstance(project).getDataManager(); + if (dataManager == null) { + presentation.setEnabledAndVisible(false); + } + else { + VcsLogIndex index = dataManager.getIndex(); + if (!(index instanceof VcsLogPersistentIndex)) { + presentation.setEnabledAndVisible(false); + } + else { + presentation.setEnabledAndVisible(!log.getSelectedCommits().isEmpty()); + } + } + } + } + } + + @Override + public void actionPerformed(AnActionEvent e) { + Project project = e.getProject(); + VcsLog log = e.getData(VcsLogDataKeys.VCS_LOG); + if (project == null || log == null) { + return; + } + VcsLogData dataManager = VcsProjectLog.getInstance(project).getDataManager(); + if (dataManager == null) return; + VcsLogIndex index = dataManager.getIndex(); + if (!(index instanceof VcsLogPersistentIndex)) return; + + List commits = log.getSelectedCommits(); + for (CommitId commit : commits) { + ((VcsLogPersistentIndex)index).printDebugInfoForCommit(commit); + } + VcsBalloonProblemNotifier.showOverChangesView(project, "Index information for " + + commits.size() + " " + + StringUtil.pluralize("commit", commits.size()) + + " was written into log file", MessageType.INFO); + } +}