diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 9d38a9e0607f..5c2c48ed64fc 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -108,6 +108,11 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().isAssociated(value, inputId); } + @Override + public IntPredicate getValueAssociationPredicate(Value value) { + return getMergedData().getValueAssociationPredicate(value); + } + @Override public IntIterator getInputIdsIterator(final Value value) { return getMergedData().getInputIdsIterator(value); @@ -119,7 +124,7 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer // need 'synchronized' to ensure atomic initialization of merged data // because several threads that acquired read lock may simultaneously execute the method - private ValueContainer getMergedData() { + private ValueContainerImpl getMergedData() { ValueContainerImpl merged = myMerged; if (merged != null) { return merged; @@ -129,16 +134,15 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer if (merged != null) { return merged; } - final ValueContainerImpl newMerged = new ValueContainerImpl(); final ValueContainer fromDisk = myInitializer.compute(); + final ValueContainerImpl newMerged; - fromDisk.forEach(new ContainerAction() { - @Override - public void perform(final int id, final Value value) { - newMerged.addValue(id, value); - } - }); + if (fromDisk instanceof ValueContainerImpl) { + newMerged = ((ValueContainerImpl)fromDisk).clone(); + } else { + newMerged = ((ChangeTrackingValueContainer)fromDisk).getMergedData().clone(); + } myInvalidated.forEach(new TIntProcedure() { @Override public boolean execute(int inputId) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 11c8420940db..0eb0089fd3c1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -63,8 +63,6 @@ import com.intellij.util.*; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ConcurrentHashSet; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.HashSet; import com.intellij.util.io.*; import com.intellij.util.io.DataOutputStream; import com.intellij.util.io.storage.HeavyProcessLatch; @@ -171,7 +169,7 @@ public class FileBasedIndex implements ApplicationComponent { @Override public void beforeFileTypesChanged(final FileTypeEvent event) { cleanupProcessedFlag(); - myTypeToExtensionMap = new HashMap>(); + myTypeToExtensionMap = new THashMap>(); for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { myTypeToExtensionMap.put(type, getExtensions(type)); } @@ -182,7 +180,7 @@ public class FileBasedIndex implements ApplicationComponent { final Map> oldExtensions = myTypeToExtensionMap; myTypeToExtensionMap = null; if (oldExtensions != null) { - final Map> newExtensions = new HashMap>(); + final Map> newExtensions = new THashMap>(); for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { newExtensions.put(type, getExtensions(type)); } @@ -204,7 +202,7 @@ public class FileBasedIndex implements ApplicationComponent { } private Set getExtensions(FileType type) { - final Set set = new HashSet(); + final Set set = new THashSet(); for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { set.add(matcher.getPresentableString()); } @@ -434,7 +432,7 @@ public class FileBasedIndex implements ApplicationComponent { } private static Set readRegisteredIndexNames() { - final Set result = new HashSet(); + final Set result = new THashSet(); try { final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); try { @@ -493,7 +491,7 @@ public class FileBasedIndex implements ApplicationComponent { MemoryIndexStorage storage) throws IOException { final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); final Ref isBufferingMode = new Ref(false); - final Map> tempMap = new HashMap>(); + final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); final DataExternalizer> dataExternalizer = new DataExternalizer>() { @Override @@ -667,7 +665,7 @@ public class FileBasedIndex implements ApplicationComponent { */ @NotNull public Collection getAllKeys(final ID indexId, @NotNull Project project) { - Set allKeys = new HashSet(); + Set allKeys = new THashSet(); processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); return allKeys; } @@ -829,7 +827,7 @@ public class FileBasedIndex implements ApplicationComponent { @NotNull public Collection getContainingFiles(final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final Set files = new HashSet(); + final Set files = new THashSet(); processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { @Override public boolean process(final VirtualFile file, final V value) { @@ -1021,7 +1019,7 @@ public class FileBasedIndex implements ApplicationComponent { for (K dataKey : dataKeys) { ProgressManager.checkCanceled(); - TIntHashSet copy = new TIntHashSet(); + final TIntHashSet copy = new TIntHashSet(); final ValueContainer container = index.getData(dataKey); for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { @@ -1029,12 +1027,27 @@ public class FileBasedIndex implements ApplicationComponent { if (valueChecker != null && !valueChecker.value(value)) { continue; } - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if ((mainIntersection == null || mainIntersection.contains(id)) && - (projectFilesFilter == null || projectFilesFilter.contains(id))) { - copy.add(id); + + ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); + + if (mainIntersection == null || iterator.size() < mainIntersection.size()) { + for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || + mainIntersection != null && mainIntersection.contains(id) + ) { + copy.add(id); + } } + } else { + mainIntersection.forEach(new TIntProcedure() { + final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); + @Override + public boolean execute(int id) { + if (predicate.contains(id)) copy.add(id); + return true; + } + }); } } @@ -1249,7 +1262,7 @@ public class FileBasedIndex implements ApplicationComponent { } private Set getUnsavedOrTransactedDocuments() { - final Set docs = new HashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); + final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); synchronized (myTransactionMap) { docs.addAll(myTransactionMap.keySet()); } @@ -2161,7 +2174,7 @@ public class FileBasedIndex implements ApplicationComponent { return; } - Set visitedRoots = new HashSet(); + Set visitedRoots = new THashSet(); for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { //important not to depend on project here, to support per-project background reindex // each client gives a project to FileBasedIndex diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java index bdfdc4b4e0bb..dfba581b400e 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java @@ -31,11 +31,17 @@ public abstract class ValueContainer { int size(); } + + static abstract class IntPredicate { + abstract boolean contains(int id); + } public abstract IntIterator getInputIdsIterator(Value value); public abstract boolean isAssociated(Value value, int inputId); - + + public abstract IntPredicate getValueAssociationPredicate(Value value); + public abstract Iterator getValueIterator(); public abstract List toValueList(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index 9a15c3fc8b12..249a2b096d3d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -17,9 +17,11 @@ package com.intellij.util.indexing; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.containers.EmptyIterator; import gnu.trove.THashMap; import gnu.trove.TIntHashSet; import gnu.trove.TIntIterator; +import gnu.trove.TObjectObjectProcedure; import java.util.*; @@ -29,7 +31,6 @@ import java.util.*; */ class ValueContainerImpl extends UpdatableValueContainer implements Cloneable{ private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.ValueContainerImpl"); - private THashMap myInputIdMapping; public ValueContainerImpl() { @@ -117,6 +118,10 @@ class ValueContainerImpl extends UpdatableValueContainer implement @Override public Iterator getValueIterator() { + if (myInputIdMapping.size() == 0) { + return EmptyIterator.getInstance(); + } + final Set values = Collections.unmodifiableSet(myInputIdMapping.keySet()); return new Iterator() { final Iterator iterator = values.iterator(); @@ -161,6 +166,28 @@ class ValueContainerImpl extends UpdatableValueContainer implement return false; } + @Override + public IntPredicate getValueAssociationPredicate(Value value) { + final Object input = myInputIdMapping.get(value); + if (input == null) return EMPTY_PREDICATE; + if (input instanceof Integer) { + return new IntPredicate() { + final int myId = (Integer)input; + @Override + public boolean contains(int id) { + return id == myId; + } + }; + } + return new IntPredicate() { + final TIntHashSet mySet = (TIntHashSet)input; + @Override + boolean contains(int id) { + return mySet.contains(id); + } + }; + } + @Override public IntIterator getInputIdsIterator(Value value) { value = maskNull(value); @@ -266,15 +293,26 @@ class ValueContainerImpl extends UpdatableValueContainer implement return null; } final THashMap cloned = map.clone(); - for (Value key : cloned.keySet()) { - final Object val = cloned.get(key); - if (val instanceof TIntHashSet) { - cloned.put(key, ((TIntHashSet)val).clone()); + cloned.forEachEntry(new TObjectObjectProcedure() { + @Override + public boolean execute(Value key, Object val) { + if (val instanceof TIntHashSet) { + cloned.put(key, ((TIntHashSet)val).clone()); + } + return true; } - } + }); + return cloned; } + private static final IntPredicate EMPTY_PREDICATE = new IntPredicate() { + @Override + public boolean contains(int id) { + return false; + } + }; + private static class IdSet extends TIntHashSet { private IdSet(final int initialCapacity, final float loadFactor) {