mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
+7
-56
@@ -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
|
||||
|
||||
+10
-70
@@ -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;
|
||||
|
||||
+95
-102
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user