summaryrefslogtreecommitdiff
path: root/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java')
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java153
1 files changed, 135 insertions, 18 deletions
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
index 3ad505baf207..ebb7911e82be 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
@@ -22,18 +22,16 @@ import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.util.Processor;
-import com.intellij.util.SmartList;
-import com.intellij.util.SystemProperties;
+import com.intellij.util.*;
import com.intellij.util.io.*;
+import com.intellij.util.io.DataOutputStream;
import gnu.trove.THashMap;
import gnu.trove.TObjectObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -56,6 +54,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
private PersistentHashMap<Integer, ByteSequence> myContents;
private PersistentHashMap<Integer, Integer> myInputsSnapshotMapping;
+ private PersistentHashMap<Integer, String> myIndexingTrace;
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
@@ -127,6 +126,10 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
cleanMapping(myInputsSnapshotMapping);
myInputsSnapshotMapping = createInputSnapshotMapping();
}
+ if (myIndexingTrace != null) {
+ cleanMapping(myIndexingTrace);
+ myIndexingTrace = createIndexingTrace();
+ }
if (myContents != null) {
cleanMapping(myContents);
myContents = createContentsIndex();
@@ -161,6 +164,31 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
}
}
+ private PersistentHashMap<Integer, String> createIndexingTrace() throws IOException {
+ assert myIndexId != null;
+ final File mapFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "indextrace");
+ try {
+ return new PersistentHashMap<Integer, String>(mapFile, EnumeratorIntegerDescriptor.INSTANCE,
+ new DataExternalizer<String>() {
+ @Override
+ public void save(@NotNull DataOutput out, String value) throws IOException {
+ out.write((byte[])CompressionUtil.compressCharSequence(value, Charset.defaultCharset()));
+ }
+
+ @Override
+ public String read(@NotNull DataInput in) throws IOException {
+ byte[] b = new byte[((InputStream)in).available()];
+ in.readFully(b);
+ return (String)CompressionUtil.uncompressCharSequence(b, Charset.defaultCharset());
+ }
+ }, 4096);
+ }
+ catch (IOException ex) {
+ IOUtil.deleteAllFilesStartingWith(mapFile);
+ throw ex;
+ }
+ }
+
private static void cleanMapping(@NotNull PersistentHashMap<?, ?> index) {
final File baseFile = index.getBaseFile();
try {
@@ -178,6 +206,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
getReadLock().lock();
doForce(myInputsIndex);
doForce(myInputsSnapshotMapping);
+ doForce(myIndexingTrace);
doForce(myContents);
myStorage.flush();
}
@@ -216,6 +245,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
finally {
doClose(myInputsIndex);
doClose(myInputsSnapshotMapping);
+ doClose(myIndexingTrace);
doClose(myContents);
}
}
@@ -283,6 +313,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
myInputsSnapshotMapping = createInputSnapshotMapping();
}
myInputsIndex = createInputsIndex();
+ if (DebugAssertions.EXTRA_SANITY_CHECKS && myIndexId != null) {
+ myIndexingTrace = createIndexingTrace();
+ }
}
@Nullable
@@ -318,7 +351,8 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (myContents != null && weProcessPhysicalContent && content != null) {
try {
- hashId = getHashOfContent((FileContent)content);
+ FileContent fileContent = (FileContent)content;
+ hashId = getHashOfContent(fileContent);
if (doReadSavedPersistentData) {
if (!myContents.isBusyReading()) { // avoid blocking read, we can calculate index value
ByteSequence bytes = myContents.get(hashId);
@@ -326,7 +360,19 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
data = deserializeSavedPersistentData(bytes);
havePersistentData = true;
if (DebugAssertions.EXTRA_SANITY_CHECKS) {
- DebugAssertions.assertTrue(myIndexer.map(content).equals(data));
+ Map<Key, Value> contentData = myIndexer.map(content);
+ boolean sameValueForSavedIndexedResultAndCurrentOne = contentData.equals(data);
+ if (!sameValueForSavedIndexedResultAndCurrentOne) {
+ DebugAssertions.error(
+ "Unexpected difference in indexing of %s by index %s, file type %s, charset %s\ndiff %s\nprevious indexed info %s",
+ fileContent.getFile(),
+ myIndexId,
+ fileContent.getFileType(),
+ ((FileContentImpl)fileContent).getCharset(),
+ buildDiff(data, contentData),
+ myIndexingTrace.get(hashId)
+ );
+ }
}
}
} else {
@@ -344,16 +390,27 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (data == null) data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
if (hashId != null && !havePersistentData) {
- savePersistentData(data, hashId, skippedReadingPersistentDataButMayHaveIt);
+ boolean saved = savePersistentData(data, hashId, skippedReadingPersistentDataButMayHaveIt);
+ if (DebugAssertions.EXTRA_SANITY_CHECKS) {
+ if (saved) {
+
+ FileContent fileContent = (FileContent)content;
+ try {
+ myIndexingTrace.put(hashId, ((FileContentImpl)fileContent).getCharset() + "," + fileContent.getFileType()+"," + fileContent.getFile().getPath() + "," +
+ ExceptionUtil.getThrowableText(new Throwable()));
+ } catch (IOException ex) {
+ LOG.error(ex);
+ }
+ }
+ }
}
ProgressManager.checkCanceled();
final NotNullComputable<Collection<Key>> oldKeysGetter;
final int savedInputId;
- if (myHasSnapshotMapping && weProcessPhysicalContent) {
+ if (myHasSnapshotMapping) {
try {
-
- oldKeysGetter = new NotNullComputable<Collection<Key>>() {
+ final NotNullComputable<Collection<Key>> keysForGivenInputId = new NotNullComputable<Collection<Key>>() {
@NotNull
@Override
public Collection<Key> compute() {
@@ -369,15 +426,38 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
}
return currentKeys;
- } catch (IOException e) {
+ }
+ catch (IOException e) {
throw new RuntimeException(e);
}
}
};
- if (content instanceof FileContent) {
- savedInputId = getHashOfContent((FileContent)content);
+ if (weProcessPhysicalContent) {
+ if (content instanceof FileContent) {
+ savedInputId = getHashOfContent((FileContent)content);
+ }
+ else {
+ savedInputId = NULL_MAPPING;
+ }
+ oldKeysGetter = keysForGivenInputId;
} else {
+ oldKeysGetter = new NotNullComputable<Collection<Key>>() {
+ @NotNull
+ @Override
+ public Collection<Key> compute() {
+ try {
+ Collection<Key> oldKeys = myInputsIndex.get(inputId);
+ if (oldKeys == null) {
+ return keysForGivenInputId.compute();
+ }
+ return oldKeys;
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
savedInputId = NULL_MAPPING;
}
} catch (IOException ex) {
@@ -429,6 +509,41 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
};
}
+ private StringBuilder buildDiff(Map<Key, Value> data, Map<Key, Value> contentData) {
+ StringBuilder moreInfo = new StringBuilder();
+ if (contentData.size() != data.size()) {
+ moreInfo.append("Indexer has different number of elements, previously ").append(data.size()).append(" after ")
+ .append(contentData.size()).append("\n");
+ } else {
+ moreInfo.append("total ").append(contentData.size()).append(" entries\n");
+ }
+
+ for(Map.Entry<Key, Value> keyValueEntry:contentData.entrySet()) {
+ if (!data.containsKey(keyValueEntry.getKey())) {
+ moreInfo.append("Previous data doesn't contain:").append(keyValueEntry.getKey()).append( " with value ").append(keyValueEntry.getValue()).append("\n");
+ }
+ else {
+ Value value = data.get(keyValueEntry.getKey());
+ if (!Comparing.equal(keyValueEntry.getValue(), value)) {
+ moreInfo.append("Previous data has different value for key:").append(keyValueEntry.getKey()).append( ", new value ").append(keyValueEntry.getValue()).append( ", oldValue:").append(value).append("\n");
+ }
+ }
+ }
+
+ for(Map.Entry<Key, Value> keyValueEntry:data.entrySet()) {
+ if (!contentData.containsKey(keyValueEntry.getKey())) {
+ moreInfo.append("New data doesn't contain:").append(keyValueEntry.getKey()).append( " with value ").append(keyValueEntry.getValue()).append("\n");
+ }
+ else {
+ Value value = contentData.get(keyValueEntry.getKey());
+ if (!Comparing.equal(keyValueEntry.getValue(), value)) {
+ moreInfo.append("New data has different value for key:").append(keyValueEntry.getKey()).append( " new value ").append(value).append( ", oldValue:").append(keyValueEntry.getValue()).append("\n");
+ }
+ }
+ }
+ return moreInfo;
+ }
+
private Map<Key, Value> deserializeSavedPersistentData(ByteSequence bytes) throws IOException {
DataInputStream stream = new DataInputStream(new UnsyncByteArrayInputStream(bytes.getBytes(), bytes.getOffset(), bytes.getLength()));
int pairs = DataInputOutputUtil.readINT(stream);
@@ -447,8 +562,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (previouslyCalculatedContentHashId == null) {
byte[] hash = content instanceof FileContentImpl ? ((FileContentImpl)content).getHash():null;
if (hash == null) {
+ Charset charset = content instanceof FileContentImpl ? ((FileContentImpl)content).getCharset() : null;
previouslyCalculatedContentHashId = ContentHashesSupport
- .calcContentHashIdWithFileType(content.getContent(), content.getFileType());
+ .calcContentHashIdWithFileType(content.getContent(), charset, content.getFileType());
} else {
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
}
@@ -459,9 +575,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private static final ThreadLocalCachedByteArray ourSpareByteArray = new ThreadLocalCachedByteArray();
- private void savePersistentData(Map<Key, Value> data, int id, boolean delayedReading) {
+ private boolean savePersistentData(Map<Key, Value> data, int id, boolean delayedReading) {
try {
- if (delayedReading && myContents.containsMapping(id)) return;
+ if (delayedReading && myContents.containsMapping(id)) return false;
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(ourSpareByteArray.getBuffer(4 * data.size()));
DataOutputStream stream = new DataOutputStream(out);
int size = data.size();
@@ -496,6 +612,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
} catch (IOException ex) {
throw new RuntimeException(ex);
}
+ return true;
}
private static final com.intellij.openapi.util.Key<Integer> ourSavedContentHashIdKey = com.intellij.openapi.util.Key.create("saved.content.hash.id");