[vcs-log] inputs index is not needed in log

* InputsIndex is null for log indexes.
* Common persistent set is used for keeping indexed status.
* Remove myEmptyCommits from paths index and myNoTrigramsCommits from trigrams index. Commits with no paths or no trigrams wont be re-indexed now since they will be stored in the persistent set.
* Remove PrintIndexInfo action, not very useful and used for debug.
* Rewrite create/dispose code for indexes. Each constructor now throws an exception if something's wrong and all indexes are cleaned-up and recreated together if it is.
This commit is contained in:
Julia Beliaeva
2016-11-10 20:12:25 +03:00
parent 0ff6d44aa7
commit 32e141ef1b
7 changed files with 143 additions and 412 deletions
@@ -20,7 +20,10 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.util.Consumer;
import com.intellij.util.PathUtilRt;
import com.intellij.util.indexing.*;
import com.intellij.util.io.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.impl.FatalErrorHandler;
import com.intellij.vcs.log.util.PersistentUtil;
@@ -36,7 +39,6 @@ import java.util.function.ObjIntConsumer;
public class VcsLogFullDetailsIndex<T> implements Disposable {
@NotNull protected static final String INDEX = "index-";
@NotNull protected static final String INDEX_INPUTS = "index-inputs-";
@NotNull protected final MyMapReduceIndex myMapReduceIndex;
@NotNull private final ID<Integer, T> myID;
@NotNull private final String myLogId;
@@ -58,13 +60,7 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
myIndexer = indexer;
myFatalErrorHandler = fatalErrorHandler;
MyMapReduceIndex result = IOUtil.openCleanOrResetBroken(() -> new MyMapReduceIndex(myIndexer, externalizer, version),
() -> {
IOUtil.deleteAllFilesStartingWith(getStorageFile(version));
IOUtil.deleteAllFilesStartingWith(getInputsStorageFile(version));
});
if (result == null) throw new IOException("Can not create " + myName + " index for " + myLogId);
myMapReduceIndex = result;
myMapReduceIndex = new MyMapReduceIndex(myIndexer, externalizer, version);
Disposer.register(disposableParent, this);
}
@@ -120,32 +116,16 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
myMapReduceIndex.flush();
}
public boolean isIndexed(int commit) throws IOException {
return myMapReduceIndex.isIndexed(commit);
}
@Override
public void dispose() {
myMapReduceIndex.dispose();
}
protected void onNotIndexableCommit(int commit) throws StorageException {
}
public void markCorrupted() {
myMapReduceIndex.markCorrupted();
}
@NotNull
private File getStorageFile(int version) {
public File getStorageFile(int version) {
return getStorageFile(INDEX + myName, myLogId, version);
}
@NotNull
private File getInputsStorageFile(int version) {
return PersistentUtil.getStorageFile(INDEX_INPUTS + myName, myLogId, version);
}
@NotNull
public static File getStorageFile(@NotNull String kind, @NotNull String id, int version) {
File subdir = new File(PersistentUtil.LOG_CACHE, kind);
@@ -153,11 +133,6 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
return new File(subdir, safeLogId + "." + version);
}
@Nullable
protected Collection<Integer> getKeysForCommit(int commit) throws IOException {
return myMapReduceIndex.getInputsIndex().get(commit);
}
private class MyMapReduceIndex extends MapReduceIndex<Integer, T, VcsFullCommitDetails> {
public MyMapReduceIndex(@NotNull DataIndexer<Integer, T, VcsFullCommitDetails> indexer,
@@ -169,33 +144,9 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
externalizer, 5000));
}
@NotNull
public PersistentHashMap<Integer, Collection<Integer>> getInputsIndex() {
return myInputsIndex;
}
public boolean isIndexed(int commitId) throws IOException {
return myInputsIndex.containsMapping(commitId);
}
@Override
protected PersistentHashMap<Integer, Collection<Integer>> createInputsIndex() throws IOException {
IndexExtension<Integer, T, VcsFullCommitDetails> extension = getExtension();
return new PersistentHashMap<>(getInputsStorageFile(extension.getVersion()),
EnumeratorIntegerDescriptor.INSTANCE,
new InputIndexDataExternalizer<>(extension.getKeyDescriptor(), myID));
}
@Override
protected void updateWithMap(int inputId, @NotNull UpdateData<Integer, T> updateData) throws StorageException {
if (((SimpleUpdateData)updateData).getNewData().isEmpty()) {
onNotIndexableCommit(inputId);
}
super.updateWithMap(inputId, updateData);
}
public void markCorrupted() {
myInputsIndex.markCorrupted();
return null;
}
@Override
@@ -16,40 +16,38 @@
package com.intellij.vcs.log.data.index;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.TrigramBuilder;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.ScalarIndexExtension;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.indexing.ValueContainer;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.impl.FatalErrorHandler;
import com.intellij.vcs.log.util.PersistentSet;
import com.intellij.vcs.log.util.PersistentUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex<Void> {
private static final Logger LOG = Logger.getInstance(VcsLogMessagesTrigramIndex.class);
private static final String TRIGRAMS = "trigrams";
import static com.intellij.vcs.log.data.index.VcsLogPersistentIndex.getVersion;
@NotNull private final PersistentSet<Integer> myNoTrigramsCommits;
public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex<Void> {
private static final String TRIGRAMS = "trigrams";
public VcsLogMessagesTrigramIndex(@NotNull String logId,
@NotNull FatalErrorHandler fatalErrorHandler,
@NotNull Disposable disposableParent) throws IOException {
super(logId, TRIGRAMS, VcsLogPersistentIndex.getVersion(), new TrigramMessageIndexer(), ScalarIndexExtension.VOID_DATA_EXTERNALIZER,
super(logId, TRIGRAMS, getVersion(), new TrigramMessageIndexer(), ScalarIndexExtension.VOID_DATA_EXTERNALIZER,
fatalErrorHandler, disposableParent);
}
myNoTrigramsCommits =
PersistentUtil.createPersistentSet(EnumeratorIntegerDescriptor.INSTANCE, "index-no-" + TRIGRAMS, logId,
VcsLogPersistentIndex.getVersion());
@NotNull
public static Collection<File> getStorageFiles(@NotNull String logId) {
return Collections.singletonList(getStorageFile(TRIGRAMS, logId, getVersion()));
}
@Nullable
@@ -62,64 +60,6 @@ public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex<Void> {
return getCommitsWithAllKeys(trigramProcessor.map.keySet());
}
@Override
protected void onNotIndexableCommit(int commit) throws StorageException {
try {
myNoTrigramsCommits.put(commit);
}
catch (IOException e) {
throw new StorageException(e);
}
}
@Override
public boolean isIndexed(int commit) throws IOException {
return super.isIndexed(commit) || myNoTrigramsCommits.contains(commit);
}
@Override
public void flush() throws StorageException {
super.flush();
myNoTrigramsCommits.flush();
}
@Override
public void dispose() {
super.dispose();
try {
myNoTrigramsCommits.close();
}
catch (IOException e) {
LOG.warn(e);
}
}
@Override
public void markCorrupted() {
super.markCorrupted();
myNoTrigramsCommits.markCorrupted();
}
@NotNull
public String getTrigramInfo(int commit) throws IOException {
if (myNoTrigramsCommits.contains(commit)) {
return "No trigrams";
}
Collection<Integer> 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<Integer, Void, VcsFullCommitDetails> {
@NotNull
@Override
@@ -33,7 +33,6 @@ import com.intellij.util.text.CaseInsensitiveStringHashingStrategy;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.impl.FatalErrorHandler;
import com.intellij.vcs.log.impl.VcsChangesLazilyParsedDetails;
import com.intellij.vcs.log.util.PersistentSet;
import com.intellij.vcs.log.util.PersistentUtil;
import gnu.trove.THashMap;
import gnu.trove.TIntHashSet;
@@ -43,72 +42,50 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static com.intellij.util.containers.ContainerUtil.newTroveSet;
import static com.intellij.vcs.log.data.index.VcsLogPersistentIndex.getVersion;
public class VcsLogPathsIndex extends VcsLogFullDetailsIndex<Integer> {
private static final Logger LOG = Logger.getInstance(VcsLogPathsIndex.class);
private static final String NAME = "paths";
private static final String PATHS = "paths";
private static final String INDEX_PATHS_IDS = "index-paths-ids";
@NotNull private final PersistentSet<Integer> myEmptyCommits;
@NotNull private final PathsIndexer myPathsIndexer;
public VcsLogPathsIndex(@NotNull String logId,
@NotNull Set<VirtualFile> roots,
@NotNull FatalErrorHandler fatalErrorHandler,
@NotNull Disposable disposableParent) throws IOException {
super(logId, NAME, VcsLogPersistentIndex.getVersion(), new PathsIndexer(createPathsEnumerator(logId), roots),
super(logId, PATHS, getVersion(), new PathsIndexer(createPathsEnumerator(logId), roots),
new NullableIntKeyDescriptor(), fatalErrorHandler, disposableParent);
myEmptyCommits = PersistentUtil.createPersistentSet(EnumeratorIntegerDescriptor.INSTANCE, "index-no-" + NAME, logId,
VcsLogPersistentIndex.getVersion());
myPathsIndexer = (PathsIndexer)myIndexer;
myPathsIndexer.setFatalErrorConsumer(e -> {
fatalErrorHandler.consume(this, e);
markCorrupted();
});
myPathsIndexer.setFatalErrorConsumer(e -> fatalErrorHandler.consume(this, e));
}
@NotNull
private static PersistentEnumeratorBase<String> createPathsEnumerator(@NotNull String logId) throws IOException {
int version = VcsLogPersistentIndex.getVersion();
final File storageFile = PersistentUtil.getStorageFile("index-paths-ids", logId, version);
File storageFile = PersistentUtil.getStorageFile(INDEX_PATHS_IDS, logId, getVersion());
PersistentBTreeEnumerator<String> enumerator = IOUtil.openCleanOrResetBroken(
() -> new PersistentBTreeEnumerator<>(storageFile, SystemInfo.isFileSystemCaseSensitive ? EnumeratorStringDescriptor.INSTANCE
: new ToLowerCaseStringDescriptor(),
Page.PAGE_SIZE, null, version),
() -> {
IOUtil.deleteAllFilesStartingWith(getStorageFile(INDEX + NAME, logId, version));
IOUtil.deleteAllFilesStartingWith(getStorageFile(INDEX_INPUTS + NAME, logId, version));
IOUtil.deleteAllFilesStartingWith(storageFile);
});
if (enumerator == null) throw new IOException("Can not create enumerator " + NAME + " for " + logId);
return enumerator;
return new PersistentBTreeEnumerator<>(storageFile, SystemInfo.isFileSystemCaseSensitive ? EnumeratorStringDescriptor.INSTANCE
: new ToLowerCaseStringDescriptor(),
Page.PAGE_SIZE, null, getVersion());
}
@Override
protected void onNotIndexableCommit(int commit) throws StorageException {
try {
myEmptyCommits.put(commit);
}
catch (IOException e) {
throw new StorageException(e);
}
}
@Override
public boolean isIndexed(int commit) throws IOException {
return super.isIndexed(commit) || myEmptyCommits.contains(commit);
@NotNull
public static Collection<File> getStorageFiles(@NotNull String logId) {
return Arrays.asList(PersistentUtil.getStorageFile(INDEX_PATHS_IDS, logId, getVersion()),
getStorageFile(PATHS, logId, getVersion()));
}
@Override
public void flush() throws StorageException {
super.flush();
myEmptyCommits.flush();
myPathsIndexer.getPathsEnumerator().force();
}
@@ -148,12 +125,6 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex<Integer> {
@Override
public void dispose() {
super.dispose();
try {
myEmptyCommits.close();
}
catch (IOException e) {
LOG.warn(e);
}
try {
myPathsIndexer.getPathsEnumerator().close();
}
@@ -162,26 +133,6 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex<Integer> {
}
}
@Override
public void markCorrupted() {
super.markCorrupted();
myEmptyCommits.markCorrupted();
}
@NotNull
public String getPathInfo(int commit) throws IOException {
if (myEmptyCommits.contains(commit)) {
return "No paths";
}
Collection<Integer> 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<Integer, Integer, VcsFullCommitDetails> {
@NotNull private final PersistentEnumeratorBase<String> myPathsEnumerator;
@NotNull private final Set<String> myRoots;
@@ -23,25 +23,24 @@ import com.intellij.openapi.progress.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.EmptyConsumer;
import com.intellij.util.Processor;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.EmptyIntHashSet;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.indexing.ValueContainer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import com.intellij.util.io.PersistentMap;
import com.intellij.util.io.*;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.*;
import com.intellij.vcs.log.impl.FatalErrorHandler;
import com.intellij.vcs.log.impl.VcsLogUtil;
import com.intellij.vcs.log.impl.VcsLogUserFilterImpl;
import com.intellij.vcs.log.impl.VcsLogUtil;
import com.intellij.vcs.log.util.PersistentSet;
import com.intellij.vcs.log.util.PersistentUtil;
import com.intellij.vcs.log.util.StopWatch;
import com.intellij.vcs.log.util.TroveUtil;
@@ -68,10 +67,7 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull private final VcsUserRegistryImpl myUserRegistry;
@NotNull private final Set<VirtualFile> myRoots;
@NotNull private final PersistentMap<Integer, String> myMessagesIndex;
@Nullable private final VcsLogMessagesTrigramIndex myTrigramIndex;
@Nullable private final VcsLogUserIndex myUserIndex;
@Nullable private final VcsLogPathsIndex myPathsIndex;
@Nullable private final MyIndexStorage myIndexStorage;
@NotNull private final SingleTaskController<IndexingRequest, Void> mySingleTaskController = new MySingleTaskController();
@NotNull private final Map<VirtualFile, AtomicInteger> myNumberOfTasks = ContainerUtil.newHashMap();
@@ -99,12 +95,7 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(myProject, VcsUserRegistry.class);
String logId = PersistentUtil.calcLogId(myProject, providers);
myMessagesIndex = createMap(EnumeratorStringDescriptor.INSTANCE, "messages", logId, 0);
myTrigramIndex = createIndex(() -> new VcsLogMessagesTrigramIndex(logId, fatalErrorsConsumer, this));
myUserIndex = createIndex(() -> new VcsLogUserIndex(logId, myUserRegistry, fatalErrorsConsumer, this));
myPathsIndex = createIndex(() -> new VcsLogPathsIndex(logId, myRoots, fatalErrorsConsumer, this));
myIndexStorage = createIndexStorage(fatalErrorsConsumer, PersistentUtil.calcLogId(myProject, providers));
for (VirtualFile root : myRoots) {
myNumberOfTasks.put(root, new AtomicInteger());
@@ -113,14 +104,10 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
Disposer.register(disposableParent, this);
}
public static int getVersion() {
return VcsLogStorageImpl.VERSION + VERSION;
}
@Nullable
private <I extends VcsLogFullDetailsIndex> I createIndex(@NotNull ThrowableComputable<I, IOException> computable) {
protected MyIndexStorage createIndexStorage(@NotNull FatalErrorHandler fatalErrorHandler, @NotNull String logId) {
try {
return computable.compute();
return IOUtil.openCleanOrResetBroken(() -> new MyIndexStorage(logId, myUserRegistry, myRoots, fatalErrorHandler, this),
() -> MyIndexStorage.cleanup(logId));
}
catch (IOException e) {
myFatalErrorsConsumer.consume(this, e);
@@ -128,17 +115,8 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
return null;
}
@NotNull
private <V> PersistentMap<Integer, V> createMap(@NotNull KeyDescriptor<V> descriptor,
@NotNull String kind,
@NotNull String logId, int version) {
try {
return PersistentUtil.createPersistentHashMap(descriptor, kind, logId, version);
}
catch (IOException e) {
myFatalErrorsConsumer.consume(this, e);
return new InMemoryMap<>();
}
public static int getVersion() {
return VcsLogStorageImpl.VERSION + VERSION;
}
@Override
@@ -155,14 +133,17 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
}
private void storeDetails(@NotNull List<? extends VcsFullCommitDetails> details, boolean flush) {
if (myIndexStorage == null) return;
try {
for (VcsFullCommitDetails detail : details) {
int index = myHashMap.getCommitIndex(detail.getId(), detail.getRoot());
myMessagesIndex.put(index, detail.getFullMessage());
if (myTrigramIndex != null) myTrigramIndex.update(index, detail);
if (myUserIndex != null) myUserIndex.update(index, detail);
if (myPathsIndex != null) myPathsIndex.update(index, detail);
myIndexStorage.messages.put(index, detail.getFullMessage());
myIndexStorage.trigrams.update(index, detail);
myIndexStorage.users.update(index, detail);
myIndexStorage.paths.update(index, detail);
myIndexStorage.commits.put(index);
}
if (flush) {
flush();
@@ -175,10 +156,13 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
private void flush() {
try {
myMessagesIndex.force();
if (myTrigramIndex != null) myTrigramIndex.flush();
if (myUserIndex != null) myUserIndex.flush();
if (myPathsIndex != null) myPathsIndex.flush();
if (myIndexStorage != null) {
myIndexStorage.messages.force();
myIndexStorage.trigrams.flush();
myIndexStorage.users.flush();
myIndexStorage.paths.flush();
myIndexStorage.commits.flush();
}
}
catch (StorageException e) {
myFatalErrorsConsumer.consume(this, e);
@@ -186,19 +170,13 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
}
public void markCorrupted() {
if (myMessagesIndex instanceof PersistentHashMap) ((PersistentHashMap)myMessagesIndex).markCorrupted();
if (myTrigramIndex != null) myTrigramIndex.markCorrupted();
if (myUserIndex != null) myUserIndex.markCorrupted();
if (myPathsIndex != null) myPathsIndex.markCorrupted();
if (myIndexStorage != null) myIndexStorage.commits.markCorrupted();
}
@Override
public boolean isIndexed(int commit) {
try {
return myMessagesIndex.get(commit) != null &&
(myUserIndex == null || myUserIndex.isIndexed(commit)) &&
(myPathsIndex == null || myPathsIndex.isIndexed(commit)) &&
(myTrigramIndex == null || myTrigramIndex.isIndexed(commit));
return myIndexStorage == null || myIndexStorage.commits.contains(commit);
}
catch (IOException e) {
myFatalErrorsConsumer.consume(this, e);
@@ -225,6 +203,7 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull
private <T> TIntHashSet filter(@NotNull PersistentMap<Integer, T> map, @NotNull Condition<T> condition) {
TIntHashSet result = new TIntHashSet();
if (myIndexStorage == null) return result;
try {
Processor<Integer> processor = integer -> {
try {
@@ -241,11 +220,11 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
}
return true;
};
if (myMessagesIndex instanceof PersistentHashMap) {
((PersistentHashMap<Integer, T>)myMessagesIndex).processKeysWithExistingMapping(processor);
if (myIndexStorage.messages instanceof PersistentHashMap) {
((PersistentHashMap<Integer, T>)myIndexStorage.messages).processKeysWithExistingMapping(processor);
}
else {
myMessagesIndex.processKeys(processor);
myIndexStorage.messages.processKeys(processor);
}
}
catch (IOException e) {
@@ -257,9 +236,9 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull
private TIntHashSet filterUsers(@NotNull Set<VcsUser> users) {
if (myUserIndex != null) {
if (myIndexStorage != null) {
try {
return myUserIndex.getCommitsForUsers(users);
return myIndexStorage.users.getCommitsForUsers(users);
}
catch (IOException | StorageException e) {
myFatalErrorsConsumer.consume(this, e);
@@ -270,9 +249,9 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull
private TIntHashSet filterPaths(@NotNull Collection<FilePath> paths) {
if (myPathsIndex != null) {
if (myIndexStorage != null) {
try {
return myPathsIndex.getCommitsForPaths(paths);
return myIndexStorage.paths.getCommitsForPaths(paths);
}
catch (IOException | StorageException e) {
myFatalErrorsConsumer.consume(this, e);
@@ -283,20 +262,20 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull
public TIntHashSet filterMessages(@NotNull String text) {
if (myTrigramIndex != null) {
if (myIndexStorage != null) {
try {
if (VcsLogUtil.isRegexp(text)) {
Pattern pattern = Pattern.compile(text);
return filter(myMessagesIndex, message -> pattern.matcher(message).find());
return filter(myIndexStorage.messages, message -> pattern.matcher(message).find());
}
else {
ValueContainer.IntIterator commitsForSearch = myTrigramIndex.getCommitsForSubstring(text);
ValueContainer.IntIterator commitsForSearch = myIndexStorage.trigrams.getCommitsForSubstring(text);
if (commitsForSearch != null) {
TIntHashSet result = new TIntHashSet();
while (commitsForSearch.hasNext()) {
int commit = commitsForSearch.next();
try {
String value = myMessagesIndex.get(commit);
String value = myIndexStorage.messages.get(commit);
if (value != null) {
if (StringUtil.containsIgnoreCase(value, text)) {
result.add(commit);
@@ -315,18 +294,20 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
catch (StorageException e) {
myFatalErrorsConsumer.consume(this, e);
}
return filter(myIndexStorage.messages, message -> StringUtil.containsIgnoreCase(message, text));
}
return filter(myMessagesIndex, message -> StringUtil.containsIgnoreCase(message, text));
return EmptyIntHashSet.INSTANCE;
}
@Override
public boolean canFilter(@NotNull List<VcsLogDetailsFilter> filters) {
if (filters.isEmpty()) return false;
if (filters.isEmpty() || myIndexStorage == null) return false;
for (VcsLogDetailsFilter filter : filters) {
if (filter instanceof VcsLogTextFilter && myTrigramIndex != null ||
filter instanceof VcsLogUserFilterImpl && myUserIndex != null ||
filter instanceof VcsLogStructureFilter && myPathsIndex != null) {
if (filter instanceof VcsLogTextFilter ||
filter instanceof VcsLogUserFilterImpl ||
filter instanceof VcsLogStructureFilter) {
continue;
}
return false;
@@ -366,49 +347,61 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@Override
public void dispose() {
try {
myMessagesIndex.close();
}
catch (IOException e) {
LOG.warn(e);
}
}
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");
private static class MyIndexStorage {
private static final String COMMITS = "commits";
private static final String MESSAGES = "messages";
private static final int MESSAGES_VERSION = 0;
@NotNull private final PersistentSet<Integer> commits;
@NotNull private final PersistentMap<Integer, String> messages;
@NotNull private final VcsLogMessagesTrigramIndex trigrams;
@NotNull private final VcsLogUserIndex users;
@NotNull private final VcsLogPathsIndex paths;
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");
}
public MyIndexStorage(@NotNull String logId,
@NotNull VcsUserRegistryImpl userRegistry,
@NotNull Set<VirtualFile> roots,
@NotNull FatalErrorHandler fatalErrorHandler,
@NotNull Disposable parentDisposable)
throws IOException {
Disposable disposable = Disposer.newDisposable();
Disposer.register(parentDisposable, disposable);
try {
commits =
PersistentUtil.createPersistentSetOrFailIfBroken(EnumeratorIntegerDescriptor.INSTANCE, COMMITS, logId, getVersion());
Disposer.register(disposable, () -> catchAndWarn(commits::close));
messages = new PersistentHashMap<>(PersistentUtil.getStorageFile(MESSAGES, logId, MESSAGES_VERSION), new IntInlineKeyDescriptor(),
EnumeratorStringDescriptor.INSTANCE, Page.PAGE_SIZE);
Disposer.register(disposable, () -> catchAndWarn(messages::close));
trigrams = new VcsLogMessagesTrigramIndex(logId, fatalErrorHandler, disposable);
users = new VcsLogUserIndex(logId, userRegistry, fatalErrorHandler, disposable);
paths = new VcsLogPathsIndex(logId, roots, fatalErrorHandler, disposable);
}
catch (Throwable t) {
Disposer.dispose(disposable);
throw t;
}
}
private static void catchAndWarn(@NotNull ThrowableRunnable<IOException> runnable) {
try {
runnable.run();
}
catch (IOException e) {
LOG.error(e);
LOG.warn(e);
}
}
LOG.info(builder.toString());
private static void cleanup(@NotNull String logId) {
IOUtil.deleteAllFilesStartingWith(PersistentUtil.getStorageFile(COMMITS, logId, getVersion()));
IOUtil.deleteAllFilesStartingWith(PersistentUtil.getStorageFile(MESSAGES, logId, MESSAGES_VERSION));
VcsLogMessagesTrigramIndex.getStorageFiles(logId).forEach(IOUtil::deleteAllFilesStartingWith);
VcsLogUserIndex.getStorageFiles(logId).forEach(IOUtil::deleteAllFilesStartingWith);
VcsLogPathsIndex.getStorageFiles(logId).forEach(IOUtil::deleteAllFilesStartingWith);
}
}
@@ -31,26 +31,33 @@ import gnu.trove.THashMap;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import static com.intellij.vcs.log.data.index.VcsLogPersistentIndex.getVersion;
public class VcsLogUserIndex extends VcsLogFullDetailsIndex<Void> {
private static final Logger LOG = Logger.getInstance(VcsLogUserIndex.class);
private static final String USERS = "users";
@NotNull private final VcsUserRegistryImpl myUserRegistry;
public VcsLogUserIndex(@NotNull String logId,
@NotNull VcsUserRegistryImpl userRegistry,
@NotNull FatalErrorHandler consumer,
@NotNull Disposable disposableParent) throws IOException {
super(logId, "users", VcsLogPersistentIndex.getVersion(), new UserIndexer(userRegistry), ScalarIndexExtension.VOID_DATA_EXTERNALIZER,
super(logId, USERS, getVersion(), new UserIndexer(userRegistry), ScalarIndexExtension.VOID_DATA_EXTERNALIZER,
consumer, disposableParent);
myUserRegistry = userRegistry;
((UserIndexer)myIndexer).setFatalErrorConsumer(e -> {
consumer.consume(this, e);
markCorrupted();
});
((UserIndexer)myIndexer).setFatalErrorConsumer(e -> consumer.consume(this, e));
}
@NotNull
public static Collection<File> getStorageFiles(@NotNull String logId) {
return Collections.singletonList(getStorageFile(USERS, logId, getVersion()));
}
public TIntHashSet getCommitsForUsers(@NotNull Set<VcsUser> users) throws IOException, StorageException {
@@ -61,14 +68,6 @@ public class VcsLogUserIndex extends VcsLogFullDetailsIndex<Void> {
return getCommitsWithAnyKey(ids);
}
@NotNull
public String getUserInfo(int commit) throws IOException {
Collection<Integer> 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<Integer, Void, VcsFullCommitDetails> {
@NotNull private final VcsUserRegistryImpl myRegistry;
@NotNull private Consumer<Exception> myFatalErrorConsumer = LOG::error;
@@ -1,88 +0,0 @@
/*
* 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<CommitId> 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);
}
}
@@ -75,27 +75,12 @@ public class PersistentUtil {
}
@NotNull
public static <T> PersistentSet<T> createPersistentSet(@NotNull KeyDescriptor<T> keyDescriptor,
@NotNull String storageKind,
@NotNull String logId,
int version) throws IOException {
public static <T> PersistentSet<T> createPersistentSetOrFailIfBroken(@NotNull KeyDescriptor<T> keyDescriptor,
@NotNull String storageKind,
@NotNull String logId,
int version) throws IOException {
File storageFile = getStorageFile(storageKind, logId, version);
return IOUtil.openCleanOrResetBroken(() ->
new PersistentSetImpl<>(storageFile, keyDescriptor, Page.PAGE_SIZE, null, version),
storageFile);
}
@NotNull
public static <V> PersistentHashMap<Integer, V> createPersistentHashMap(@NotNull DataExternalizer<V> externalizer,
@NotNull String storageKind,
@NotNull String logId,
int version) throws IOException {
File storageFile = getStorageFile(storageKind, logId, version);
return IOUtil.openCleanOrResetBroken(() ->
new PersistentHashMap<>(storageFile, new IntInlineKeyDescriptor(), externalizer, Page.PAGE_SIZE),
storageFile);
return new PersistentSetImpl<>(storageFile, keyDescriptor, Page.PAGE_SIZE, null, version);
}
@NotNull