mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
refactor MapReduceIndex to have simple constructor arguments and all index implementation inside
This commit is contained in:
@@ -24,7 +24,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditor
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileTypes.PlainTextFileType
|
||||
import com.intellij.openapi.util.Factory
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -71,7 +70,7 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testUpdate() throws StorageException, IOException {
|
||||
StringIndex index = createIndex(new EnumeratorStringDescriptor())
|
||||
StringIndex index = createIndex(getTestName(false), new EnumeratorStringDescriptor())
|
||||
|
||||
try {
|
||||
// build index
|
||||
@@ -118,7 +117,7 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testUpdateWithCustomEqualityPolicy() {
|
||||
def index = createIndex(new CaseInsensitiveEnumeratorStringDescriptor())
|
||||
def index = createIndex(getTestName(false), new CaseInsensitiveEnumeratorStringDescriptor())
|
||||
try {
|
||||
index.update("a.java", "x", null)
|
||||
assertDataEquals(index.getFilesByWord("x"), "a.java")
|
||||
@@ -136,21 +135,12 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private static StringIndex createIndex(EnumeratorStringDescriptor keyDescriptor) {
|
||||
private static StringIndex createIndex(String testName, EnumeratorStringDescriptor keyDescriptor) {
|
||||
final File storageFile = FileUtil.createTempFile("index_test", "storage");
|
||||
final File metaIndexFile = FileUtil.createTempFile("index_test_inputs", "storage");
|
||||
PersistentHashMap<Integer, Collection<String>> index = createMetaIndex(metaIndexFile);
|
||||
final MapIndexStorage indexStorage = new MapIndexStorage(storageFile, keyDescriptor, new EnumeratorStringDescriptor(), 16 * 1024);
|
||||
return new StringIndex(indexStorage, new Factory<PersistentHashMap<Integer, Collection<String>>>() {
|
||||
@Override
|
||||
public PersistentHashMap<Integer, Collection<String>> create() {
|
||||
try {
|
||||
return createMetaIndex(metaIndexFile);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return new StringIndex(testName, indexStorage, index);
|
||||
}
|
||||
|
||||
private static PersistentHashMap<Integer, Collection<String>> createMetaIndex(File metaIndexFile) throws IOException {
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
*/
|
||||
package com.intellij.index;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.indexing.DataIndexer;
|
||||
import com.intellij.util.indexing.IndexStorage;
|
||||
import com.intellij.util.indexing.MapReduceIndex;
|
||||
import com.intellij.util.indexing.StorageException;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.io.PersistentHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -37,12 +36,44 @@ import java.util.Map;
|
||||
public class StringIndex {
|
||||
private final MapReduceIndex<String, String, PathContentPair> myIndex;
|
||||
|
||||
public StringIndex(final IndexStorage<String, String> storage, final Factory<PersistentHashMap<Integer, Collection<String>>> factory)
|
||||
public StringIndex(String testName, final IndexStorage<String, String> storage, final PersistentHashMap<Integer, Collection<String>> inputIndex)
|
||||
throws IOException {
|
||||
myIndex = new MapReduceIndex<String, String, PathContentPair>(null, new Indexer(), storage);
|
||||
myIndex.setInputIdToDataKeysIndex(factory);
|
||||
myIndex = new MapReduceIndex<String, String, PathContentPair>(new IndexExtension<String, String, PathContentPair>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<String, String> getName() {
|
||||
return new ID<String, String>(testName + "string_index") {};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<String, String, PathContentPair> getIndexer() {
|
||||
return new Indexer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<String> getKeyDescriptor() {
|
||||
return new EnumeratorStringDescriptor();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<String> getValueExternalizer() {
|
||||
return new EnumeratorStringDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
}, storage) {
|
||||
protected PersistentHashMap<Integer, Collection<String>> createInputsIndex() throws IOException {
|
||||
return inputIndex;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public List<String> getFilesByWord(@NotNull String word) throws StorageException {
|
||||
return myIndex.getData(word).toValueList();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -30,22 +28,10 @@ import java.util.Collections;
|
||||
* Date: Dec 26, 2007
|
||||
* V class MUST have equals / hashcode properly defined!!!
|
||||
*/
|
||||
public abstract class FileBasedIndexExtension<K, V> {
|
||||
public abstract class FileBasedIndexExtension<K, V> extends IndexExtension<K, V, FileContent>{
|
||||
public static final ExtensionPointName<FileBasedIndexExtension> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.fileBasedIndex");
|
||||
public static final int DEFAULT_CACHE_SIZE = 1024;
|
||||
|
||||
@NotNull
|
||||
public abstract ID<K, V> getName();
|
||||
|
||||
@NotNull
|
||||
public abstract DataIndexer<K, V, FileContent> getIndexer();
|
||||
|
||||
@NotNull
|
||||
public abstract KeyDescriptor<K> getKeyDescriptor();
|
||||
|
||||
@NotNull
|
||||
public abstract DataExternalizer<V> getValueExternalizer();
|
||||
|
||||
@NotNull
|
||||
public abstract FileBasedIndex.InputFilter getInputFilter();
|
||||
|
||||
@@ -55,8 +41,6 @@ public abstract class FileBasedIndexExtension<K, V> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract int getVersion();
|
||||
|
||||
/**
|
||||
* @see FileBasedIndexExtension#DEFAULT_CACHE_SIZE
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.util.indexing;
|
||||
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: Dec 26, 2007
|
||||
* V class MUST have equals / hashcode properly defined!!!
|
||||
*/
|
||||
public abstract class IndexExtension<K, V, I> {
|
||||
@NotNull
|
||||
public abstract ID<K, V> getName();
|
||||
|
||||
@NotNull
|
||||
public abstract DataIndexer<K, V, I> getIndexer();
|
||||
|
||||
@NotNull
|
||||
public abstract KeyDescriptor<K> getKeyDescriptor();
|
||||
|
||||
@NotNull
|
||||
public abstract DataExternalizer<V> getValueExternalizer();
|
||||
|
||||
public abstract int getVersion();
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
@@ -112,17 +113,47 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
try {
|
||||
StubIdExternalizer externalizer = new StubIdExternalizer();
|
||||
final MapIndexStorage<K, StubIdList> storage = new MapIndexStorage<K, StubIdList>(
|
||||
IndexInfrastructure.getStorageFile(indexKey),
|
||||
extension.getKeyDescriptor(),
|
||||
new StubIdExternalizer(),
|
||||
externalizer,
|
||||
extension.getCacheSize(),
|
||||
false,
|
||||
extension instanceof StringStubIndexExtension && ((StringStubIndexExtension)extension).traceKeyHashToVirtualFileMapping()
|
||||
);
|
||||
|
||||
final MemoryIndexStorage<K, StubIdList> memStorage = new MemoryIndexStorage<K, StubIdList>(storage);
|
||||
myIndices.put(indexKey, new MyIndex<K>(memStorage));
|
||||
myIndices.put(indexKey, new MyIndex<K>(new IndexExtension<K, StubIdList, Void>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<K, StubIdList> getName() {
|
||||
return (ID<K, StubIdList>)indexKey;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<K, StubIdList, Void> getIndexer() {
|
||||
return inputData -> Collections.emptyMap();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<K> getKeyDescriptor() {
|
||||
return extension.getKeyDescriptor();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<StubIdList> getValueExternalizer() {
|
||||
return externalizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return extension.getVersion();
|
||||
}
|
||||
}, memStorage));
|
||||
break;
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -512,8 +543,8 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
}
|
||||
|
||||
private static class MyIndex<K> extends MapReduceIndex<K, StubIdList, Void> {
|
||||
public MyIndex(final IndexStorage<K, StubIdList> storage) throws IOException {
|
||||
super(null, null, storage);
|
||||
public MyIndex(IndexExtension<K, StubIdList, Void> extension, IndexStorage<K, StubIdList> storage) throws IOException {
|
||||
super(extension, storage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -230,7 +230,8 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation(@NotNull final ID<Integer, SerializedStubTree> indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage<Integer, SerializedStubTree> storage)
|
||||
public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation(@NotNull final FileBasedIndexExtension<Integer, SerializedStubTree> extension,
|
||||
@NotNull IndexStorage<Integer, SerializedStubTree> storage)
|
||||
throws StorageException, IOException {
|
||||
if (storage instanceof MemoryIndexStorage) {
|
||||
final MemoryIndexStorage<Integer, SerializedStubTree> memStorage = (MemoryIndexStorage<Integer, SerializedStubTree>)storage;
|
||||
@@ -246,7 +247,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
}
|
||||
});
|
||||
}
|
||||
return new MyIndex(indexId, storage, getIndexer());
|
||||
return new MyIndex(extension, storage);
|
||||
}
|
||||
|
||||
private static void updateStubIndices(@NotNull final Collection<StubIndexKey> indexKeys,
|
||||
@@ -277,9 +278,9 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
private static class MyIndex extends MapReduceIndex<Integer, SerializedStubTree, FileContent> {
|
||||
private StubIndexImpl myStubIndex;
|
||||
|
||||
public MyIndex(final ID<Integer, SerializedStubTree> indexId, final IndexStorage<Integer, SerializedStubTree> storage, final DataIndexer<Integer, SerializedStubTree, FileContent> indexer)
|
||||
public MyIndex(FileBasedIndexExtension<Integer, SerializedStubTree> extension, IndexStorage<Integer, SerializedStubTree> storage)
|
||||
throws StorageException, IOException {
|
||||
super(indexId, indexer, storage);
|
||||
super(extension, storage);
|
||||
checkNameStorage();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -25,6 +25,7 @@ import java.io.IOException;
|
||||
|
||||
public abstract class CustomImplementationFileBasedIndexExtension<K, V, I> extends FileBasedIndexExtension<K, V> {
|
||||
@NotNull
|
||||
public abstract UpdatableIndex<K, V, I> createIndexImplementation(@NotNull ID<K, V> indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage<K, V> storage)
|
||||
public abstract UpdatableIndex<K, V, I> createIndexImplementation(@NotNull FileBasedIndexExtension<K, V> extension,
|
||||
@NotNull IndexStorage<K, V> storage)
|
||||
throws StorageException, IOException;
|
||||
}
|
||||
@@ -73,8 +73,8 @@ import com.intellij.psi.stubs.SerializationManagerEx;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ConcurrentIntObjectMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.*;
|
||||
import com.intellij.util.io.DataOutputStream;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import com.intellij.util.io.storage.HeavyProcessLatch;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
@@ -536,124 +536,26 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <K, V> UpdatableIndex<K, V, FileContent> createIndex(@NotNull final ID<K, V> indexId,
|
||||
private static <K, V> UpdatableIndex<K, V, FileContent> createIndex(@NotNull final ID<K, V> indexId,
|
||||
@NotNull final FileBasedIndexExtension<K, V> extension,
|
||||
@NotNull final MemoryIndexStorage<K, V> storage)
|
||||
throws StorageException, IOException {
|
||||
final MapReduceIndex<K, V, FileContent> index;
|
||||
if (extension instanceof CustomImplementationFileBasedIndexExtension) {
|
||||
final UpdatableIndex<K, V, FileContent> custom =
|
||||
((CustomImplementationFileBasedIndexExtension<K, V, FileContent>)extension).createIndexImplementation(indexId, this, storage);
|
||||
((CustomImplementationFileBasedIndexExtension<K, V, FileContent>)extension).createIndexImplementation(extension, storage);
|
||||
if (!(custom instanceof MapReduceIndex)) {
|
||||
return custom;
|
||||
}
|
||||
index = (MapReduceIndex<K, V, FileContent>)custom;
|
||||
}
|
||||
else {
|
||||
DataExternalizer<Collection<K>> externalizer =
|
||||
extension.hasSnapshotMapping() && IdIndex.ourSnapshotMappingsEnabled
|
||||
? createInputsIndexExternalizer(extension, indexId, extension.getKeyDescriptor())
|
||||
: null;
|
||||
index = new MapReduceIndex<K, V, FileContent>(
|
||||
indexId, extension.getIndexer(), storage, externalizer, extension.getValueExternalizer(), extension instanceof PsiDependentIndex);
|
||||
index = new MapReduceIndex<K, V, FileContent>(extension, storage);
|
||||
}
|
||||
index.setInputIdToDataKeysIndex(new Factory<PersistentHashMap<Integer, Collection<K>>>() {
|
||||
@Override
|
||||
public PersistentHashMap<Integer, Collection<K>> create() {
|
||||
try {
|
||||
return createIdToDataKeysIndex(extension, storage);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(@NotNull FileBasedIndexExtension <K, ?> extension,
|
||||
@NotNull MemoryIndexStorage<K, ?> storage)
|
||||
throws IOException {
|
||||
ID<K, ?> indexId = extension.getName();
|
||||
KeyDescriptor<K> keyDescriptor = extension.getKeyDescriptor();
|
||||
final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId);
|
||||
final AtomicBoolean isBufferingMode = new AtomicBoolean();
|
||||
final TIntObjectHashMap<Collection<K>> tempMap = new TIntObjectHashMap<Collection<K>>();
|
||||
|
||||
// Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage.
|
||||
// If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage).
|
||||
// Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the
|
||||
// wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be
|
||||
// cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects.
|
||||
|
||||
final PersistentHashMap<Integer, Collection<K>> map = new PersistentHashMap<Integer, Collection<K>>(
|
||||
indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, createInputsIndexExternalizer(extension, indexId, keyDescriptor)
|
||||
) {
|
||||
|
||||
@Override
|
||||
protected Collection<K> doGet(Integer integer) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
final Collection<K> collection = tempMap.get(integer);
|
||||
if (collection != null) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
return super.doGet(integer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(Integer integer, @Nullable Collection<K> ks) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
tempMap.put(integer, ks == null ? Collections.<K>emptySet() : ks);
|
||||
}
|
||||
else {
|
||||
super.doPut(integer, ks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemove(Integer integer) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
tempMap.put(integer, Collections.<K>emptySet());
|
||||
}
|
||||
else {
|
||||
super.doRemove(integer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
storage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() {
|
||||
@Override
|
||||
public void bufferingStateChanged(boolean newState) {
|
||||
synchronized (map) {
|
||||
isBufferingMode.set(newState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memoryStorageCleared() {
|
||||
synchronized (map) {
|
||||
tempMap.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
private static <K> DataExternalizer<Collection<K>> createInputsIndexExternalizer(FileBasedIndexExtension<K, ?> extension,
|
||||
ID<K, ?> indexId,
|
||||
KeyDescriptor<K> keyDescriptor) {
|
||||
DataExternalizer<Collection<K>> externalizer;
|
||||
if (extension instanceof CustomInputsIndexFileBasedIndexExtension) {
|
||||
externalizer = ((CustomInputsIndexFileBasedIndexExtension<K>)extension).createExternalizer();
|
||||
} else {
|
||||
externalizer = new InputIndexDataExternalizer<K>(keyDescriptor, indexId);
|
||||
}
|
||||
return externalizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
performShutdown();
|
||||
|
||||
@@ -26,17 +26,20 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.openapi.util.io.ByteSequence;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.cache.impl.id.IdIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.io.*;
|
||||
import com.intellij.util.io.DataOutputStream;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -55,6 +58,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
private final DataExternalizer<Value> myValueExternalizer;
|
||||
private final DataExternalizer<Collection<Key>> mySnapshotIndexExternalizer;
|
||||
private final boolean myIsPsiBackedIndex;
|
||||
private final IndexExtension<Key, Value, Input> myExtension;
|
||||
|
||||
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
|
||||
private PersistentHashMap<Integer, ByteSequence> myContents;
|
||||
@@ -63,8 +67,6 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
|
||||
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
|
||||
|
||||
private Factory<PersistentHashMap<Integer, Collection<Key>>> myInputsIndexFactory;
|
||||
|
||||
private final LowMemoryWatcher myLowMemoryFlusher = LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -77,28 +79,110 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
}
|
||||
});
|
||||
|
||||
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
|
||||
DataIndexer<Key, Value, Input> indexer,
|
||||
public MapReduceIndex(IndexExtension<Key, Value, Input> extension,
|
||||
@NotNull IndexStorage<Key, Value> storage) throws IOException {
|
||||
this(indexId, indexer, storage, null, null, false);
|
||||
myIndexId = extension.getName();
|
||||
myExtension = extension;
|
||||
myIndexer = extension.getIndexer();
|
||||
myStorage = storage;
|
||||
myHasSnapshotMapping = extension instanceof FileBasedIndexExtension &&
|
||||
((FileBasedIndexExtension<Key, Value>)extension).hasSnapshotMapping() &&
|
||||
IdIndex.ourSnapshotMappingsEnabled;
|
||||
|
||||
mySnapshotIndexExternalizer = createInputsIndexExternalizer(extension, myIndexId, extension.getKeyDescriptor());
|
||||
myValueExternalizer = extension.getValueExternalizer();
|
||||
myContents = createContentsIndex();
|
||||
myIsPsiBackedIndex = extension instanceof PsiDependentIndex;
|
||||
|
||||
if (myHasSnapshotMapping) {
|
||||
myInputsSnapshotMapping = createInputSnapshotMapping();
|
||||
}
|
||||
myInputsIndex = createInputsIndex();
|
||||
if (DebugAssertions.EXTRA_SANITY_CHECKS && myHasSnapshotMapping && myIndexId != null) {
|
||||
myIndexingTrace = createIndexingTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
|
||||
DataIndexer<Key, Value, Input> indexer,
|
||||
@NotNull IndexStorage<Key, Value> storage,
|
||||
DataExternalizer<Collection<Key>> snapshotIndexExternalizer,
|
||||
DataExternalizer<Value> valueDataExternalizer,
|
||||
boolean psiBasedIndex
|
||||
) throws IOException {
|
||||
myIndexId = indexId;
|
||||
myIndexer = indexer;
|
||||
myStorage = storage;
|
||||
myHasSnapshotMapping = snapshotIndexExternalizer != null;
|
||||
private static <K> DataExternalizer<Collection<K>> createInputsIndexExternalizer(IndexExtension<K, ?, ?> extension,
|
||||
ID<K, ?> indexId,
|
||||
KeyDescriptor<K> keyDescriptor) {
|
||||
DataExternalizer<Collection<K>> externalizer;
|
||||
if (extension instanceof CustomInputsIndexFileBasedIndexExtension) {
|
||||
externalizer = ((CustomInputsIndexFileBasedIndexExtension<K>)extension).createExternalizer();
|
||||
} else {
|
||||
externalizer = new InputIndexDataExternalizer<K>(keyDescriptor, indexId);
|
||||
}
|
||||
return externalizer;
|
||||
}
|
||||
|
||||
mySnapshotIndexExternalizer = snapshotIndexExternalizer;
|
||||
myValueExternalizer = valueDataExternalizer;
|
||||
myContents = createContentsIndex();
|
||||
myIsPsiBackedIndex = psiBasedIndex;
|
||||
@NotNull
|
||||
private static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(@NotNull IndexExtension <K, ?, ?> extension,
|
||||
@NotNull MemoryIndexStorage<K, ?> storage)
|
||||
throws IOException {
|
||||
ID<K, ?> indexId = extension.getName();
|
||||
KeyDescriptor<K> keyDescriptor = extension.getKeyDescriptor();
|
||||
final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId);
|
||||
final AtomicBoolean isBufferingMode = new AtomicBoolean();
|
||||
final TIntObjectHashMap<Collection<K>> tempMap = new TIntObjectHashMap<Collection<K>>();
|
||||
|
||||
// Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage.
|
||||
// If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage).
|
||||
// Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the
|
||||
// wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be
|
||||
// cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects.
|
||||
|
||||
final PersistentHashMap<Integer, Collection<K>> map = new PersistentHashMap<Integer, Collection<K>>(
|
||||
indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, createInputsIndexExternalizer(extension, indexId, keyDescriptor)
|
||||
) {
|
||||
|
||||
@Override
|
||||
protected Collection<K> doGet(Integer integer) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
final Collection<K> collection = tempMap.get(integer);
|
||||
if (collection != null) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
return super.doGet(integer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(Integer integer, @Nullable Collection<K> ks) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
tempMap.put(integer, ks == null ? Collections.<K>emptySet() : ks);
|
||||
}
|
||||
else {
|
||||
super.doPut(integer, ks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemove(Integer integer) throws IOException {
|
||||
if (isBufferingMode.get()) {
|
||||
tempMap.put(integer, Collections.<K>emptySet());
|
||||
}
|
||||
else {
|
||||
super.doRemove(integer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
storage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() {
|
||||
@Override
|
||||
public void bufferingStateChanged(boolean newState) {
|
||||
synchronized (map) {
|
||||
isBufferingMode.set(newState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memoryStorageCleared() {
|
||||
synchronized (map) {
|
||||
tempMap.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
private PersistentHashMap<Integer, ByteSequence> createContentsIndex() throws IOException {
|
||||
@@ -315,32 +399,8 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
}
|
||||
}
|
||||
|
||||
public void setInputIdToDataKeysIndex(Factory<PersistentHashMap<Integer, Collection<Key>>> factory) throws IOException {
|
||||
myInputsIndexFactory = factory;
|
||||
if (myHasSnapshotMapping) {
|
||||
myInputsSnapshotMapping = createInputSnapshotMapping();
|
||||
}
|
||||
myInputsIndex = createInputsIndex();
|
||||
if (DebugAssertions.EXTRA_SANITY_CHECKS && myHasSnapshotMapping && myIndexId != null) {
|
||||
myIndexingTrace = createIndexingTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PersistentHashMap<Integer, Collection<Key>> createInputsIndex() throws IOException {
|
||||
Factory<PersistentHashMap<Integer, Collection<Key>>> factory = myInputsIndexFactory;
|
||||
if (factory != null) {
|
||||
try {
|
||||
return factory.create();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
if (e.getCause() instanceof IOException) {
|
||||
throw (IOException)e.getCause();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
protected PersistentHashMap<Integer, Collection<Key>> createInputsIndex() throws IOException {
|
||||
return createIdToDataKeysIndex(myExtension, (MemoryIndexStorage<Key, ?>)myStorage);
|
||||
}
|
||||
|
||||
private static final boolean doReadSavedPersistentData = SystemProperties.getBooleanProperty("idea.read.saved.persistent.index", true);
|
||||
|
||||
Reference in New Issue
Block a user