process iteration over smaller set when intersecting file sets with occurences,

also more efficient merged data calculation by cloning data retrieved from disk
This commit is contained in:
Maxim.Mossienko
2012-02-22 18:50:02 +04:00
parent cdad3805c3
commit 73e8eb6dc8
4 changed files with 93 additions and 32 deletions
@@ -108,6 +108,11 @@ class ChangeTrackingValueContainer<Value> extends UpdatableValueContainer<Value>
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<Value> extends UpdatableValueContainer<Value>
// need 'synchronized' to ensure atomic initialization of merged data
// because several threads that acquired read lock may simultaneously execute the method
private ValueContainer<Value> getMergedData() {
private ValueContainerImpl<Value> getMergedData() {
ValueContainerImpl<Value> merged = myMerged;
if (merged != null) {
return merged;
@@ -129,16 +134,15 @@ class ChangeTrackingValueContainer<Value> extends UpdatableValueContainer<Value>
if (merged != null) {
return merged;
}
final ValueContainerImpl<Value> newMerged = new ValueContainerImpl<Value>();
final ValueContainer<Value> fromDisk = myInitializer.compute();
final ValueContainerImpl<Value> newMerged;
fromDisk.forEach(new ContainerAction<Value>() {
@Override
public void perform(final int id, final Value value) {
newMerged.addValue(id, value);
}
});
if (fromDisk instanceof ValueContainerImpl) {
newMerged = ((ValueContainerImpl<Value>)fromDisk).clone();
} else {
newMerged = ((ChangeTrackingValueContainer<Value>)fromDisk).getMergedData().clone();
}
myInvalidated.forEach(new TIntProcedure() {
@Override
public boolean execute(int inputId) {
@@ -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<FileType, Set<String>>();
myTypeToExtensionMap = new THashMap<FileType, Set<String>>();
for (FileType type : myFileTypeManager.getRegisteredFileTypes()) {
myTypeToExtensionMap.put(type, getExtensions(type));
}
@@ -182,7 +180,7 @@ public class FileBasedIndex implements ApplicationComponent {
final Map<FileType, Set<String>> oldExtensions = myTypeToExtensionMap;
myTypeToExtensionMap = null;
if (oldExtensions != null) {
final Map<FileType, Set<String>> newExtensions = new HashMap<FileType, Set<String>>();
final Map<FileType, Set<String>> newExtensions = new THashMap<FileType, Set<String>>();
for (FileType type : myFileTypeManager.getRegisteredFileTypes()) {
newExtensions.put(type, getExtensions(type));
}
@@ -204,7 +202,7 @@ public class FileBasedIndex implements ApplicationComponent {
}
private Set<String> getExtensions(FileType type) {
final Set<String> set = new HashSet<String>();
final Set<String> set = new THashSet<String>();
for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) {
set.add(matcher.getPresentableString());
}
@@ -434,7 +432,7 @@ public class FileBasedIndex implements ApplicationComponent {
}
private static Set<String> readRegisteredIndexNames() {
final Set<String> result = new HashSet<String>();
final Set<String> result = new THashSet<String>();
try {
final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile())));
try {
@@ -493,7 +491,7 @@ public class FileBasedIndex implements ApplicationComponent {
MemoryIndexStorage<K, ?> storage) throws IOException {
final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId);
final Ref<Boolean> isBufferingMode = new Ref<Boolean>(false);
final Map<Integer, Collection<K>> tempMap = new HashMap<Integer, Collection<K>>();
final TIntObjectHashMap<Collection<K>> tempMap = new TIntObjectHashMap<Collection<K>>();
final DataExternalizer<Collection<K>> dataExternalizer = new DataExternalizer<Collection<K>>() {
@Override
@@ -667,7 +665,7 @@ public class FileBasedIndex implements ApplicationComponent {
*/
@NotNull
public <K> Collection<K> getAllKeys(final ID<K, ?> indexId, @NotNull Project project) {
Set<K> allKeys = new HashSet<K>();
Set<K> allKeys = new THashSet<K>();
processAllKeys(indexId, new CommonProcessors.CollectProcessor<K>(allKeys), project);
return allKeys;
}
@@ -829,7 +827,7 @@ public class FileBasedIndex implements ApplicationComponent {
@NotNull
public <K, V> Collection<VirtualFile> getContainingFiles(final ID<K, V> indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) {
final Set<VirtualFile> files = new HashSet<VirtualFile>();
final Set<VirtualFile> files = new THashSet<VirtualFile>();
processValuesImpl(indexId, dataKey, false, null, new ValueProcessor<V>() {
@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<V> container = index.getData(dataKey);
for (final Iterator<V> 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<Document> getUnsavedOrTransactedDocuments() {
final Set<Document> docs = new HashSet<Document>(Arrays.asList(myFileDocumentManager.getUnsavedDocuments()));
final Set<Document> docs = new THashSet<Document>(Arrays.asList(myFileDocumentManager.getUnsavedDocuments()));
synchronized (myTransactionMap) {
docs.addAll(myTransactionMap.keySet());
}
@@ -2161,7 +2174,7 @@ public class FileBasedIndex implements ApplicationComponent {
return;
}
Set<VirtualFile> visitedRoots = new HashSet<VirtualFile>();
Set<VirtualFile> visitedRoots = new THashSet<VirtualFile>();
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
@@ -31,11 +31,17 @@ public abstract class ValueContainer<Value> {
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<Value> getValueIterator();
public abstract List<Value> toValueList();
@@ -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<Value> extends UpdatableValueContainer<Value> implements Cloneable{
private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.ValueContainerImpl");
private THashMap<Value, Object> myInputIdMapping;
public ValueContainerImpl() {
@@ -117,6 +118,10 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement
@Override
public Iterator<Value> getValueIterator() {
if (myInputIdMapping.size() == 0) {
return EmptyIterator.getInstance();
}
final Set<Value> values = Collections.unmodifiableSet(myInputIdMapping.keySet());
return new Iterator<Value>() {
final Iterator<Value> iterator = values.iterator();
@@ -161,6 +166,28 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> 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<Value> extends UpdatableValueContainer<Value> implement
return null;
}
final THashMap<Value, Object> 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<Value, Object>() {
@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) {