Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-05-08 16:05:31 +02:00
21 changed files with 386 additions and 151 deletions
@@ -91,7 +91,7 @@ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> {
@Override
public int getVersion() {
return 11 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
return 12 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
}
@Override
@@ -103,7 +103,7 @@ public class TrigramIndex extends ScalarIndexExtension<Integer> implements Custo
@Override
public int getVersion() {
return ENABLED ? 2 + (IdIndex.ourSnapshotMappingsEnabled ? 0xFF:0) : 1;
return ENABLED ? 3 + (IdIndex.ourSnapshotMappingsEnabled ? 0xFF:0) : 1;
}
@Override
@@ -135,7 +135,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
LOG.info("Version has changed for stub index " + extension.getKey() + ". The index will be rebuilt.");
}
FileUtil.delete(indexRootDir);
IndexingStamp.rewriteVersion(versionFile, version);
IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
}
for (int attempt = 0; attempt < 2; attempt++) {
@@ -157,7 +157,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
LOG.info(e);
needRebuild = true;
FileUtil.delete(indexRootDir);
IndexingStamp.rewriteVersion(versionFile, version);
IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
}
}
return needRebuild;
@@ -445,7 +445,7 @@ 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) {
public MyIndex(final IndexStorage<K, StubIdList> storage) throws IOException {
super(null, null, storage);
}
@@ -227,7 +227,7 @@ 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)
throws StorageException {
throws StorageException, IOException {
if (storage instanceof MemoryIndexStorage) {
final MemoryIndexStorage<Integer, SerializedStubTree> memStorage = (MemoryIndexStorage<Integer, SerializedStubTree>)storage;
memStorage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() {
@@ -273,7 +273,8 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
private 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) throws StorageException {
public MyIndex(final ID<Integer, SerializedStubTree> indexId, final IndexStorage<Integer, SerializedStubTree> storage, final DataIndexer<Integer, SerializedStubTree, FileContent> indexer)
throws StorageException, IOException {
super(indexId, indexer, storage);
checkNameStorage();
}
@@ -0,0 +1,43 @@
/*
* Copyright 2000-2014 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.openapi.util.io.ByteSequence;
import com.intellij.util.io.DataExternalizer;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Maxim.Mossienko on 5/7/2014.
*/
class ByteSequenceDataExternalizer implements DataExternalizer<ByteSequence> {
static final ByteSequenceDataExternalizer INSTANCE = new ByteSequenceDataExternalizer();
@Override
public void save(@NotNull DataOutput out, ByteSequence value) throws IOException {
out.write(value.getBytes(), value.getOffset(), value.getLength()); // todo fix double copying
}
@Override
public ByteSequence read(@NotNull DataInput in) throws IOException {
byte[] buf = new byte[((InputStream)in).available()]; // todo fix double copying
in.readFully(buf);
return new ByteSequence(buf);
}
}
@@ -15,9 +15,7 @@
*/
package com.intellij.util.indexing;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.newvfs.persistent.ContentHashesUtil;
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
import com.intellij.util.io.IOUtil;
@@ -33,28 +31,27 @@ import java.security.MessageDigest;
* @since 4/10/2014.
*/
class ContentHashesSupport {
private static final ContentHashesUtil.HashEnumerator ourHashesWithFileType;
private static volatile ContentHashesUtil.HashEnumerator ourHashesWithFileType;
static {
ContentHashesUtil.HashEnumerator hashEnumerator = null;
try {
final File hashEnumeratorFile = new File(PathManager.getIndexRoot(), "hashesWithFileType");
hashEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable<ContentHashesUtil.HashEnumerator, IOException>() {
@Override
public ContentHashesUtil.HashEnumerator compute() throws IOException {
return new ContentHashesUtil.HashEnumerator(hashEnumeratorFile, null);
}
}, hashEnumeratorFile);
FlushingDaemon.everyFiveSeconds(new Runnable() {
@Override
public void run() {
if (ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
}
});
} catch (IOException ex) {
throw new RuntimeException(ex);
} finally {
ourHashesWithFileType = hashEnumerator;
static void initContentHashesEnumerator() throws IOException {
if (ourHashesWithFileType != null) return;
synchronized (ContentHashesSupport.class) {
if (ourHashesWithFileType != null) return;
ContentHashesUtil.HashEnumerator hashEnumerator = null;
final File hashEnumeratorFile = new File(IndexInfrastructure.getPersistentIndexRoot(), "hashesWithFileType");
try {
hashEnumerator = new ContentHashesUtil.HashEnumerator(hashEnumeratorFile, null);
FlushingDaemon.everyFiveSeconds(new Runnable() {
@Override
public void run() {
if (ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
}
});
ourHashesWithFileType = hashEnumerator;
} catch (IOException ex) {
IOUtil.deleteAllFilesStartingWith(hashEnumeratorFile);
throw ex;
}
}
}
@@ -21,8 +21,10 @@ package com.intellij.util.indexing;
import org.jetbrains.annotations.NotNull;
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)
throws StorageException;
throws StorageException, IOException;
}
@@ -381,7 +381,10 @@ public class FileBasedIndexImpl extends FileBasedIndex {
versionChanged = true;
LOG.info("Version has changed for index " + name + ". The index will be rebuilt.");
}
FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
if (extension.hasSnapshotMapping() && (isCurrentVersionCorrupted || versionChanged)) {
safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name));
}
safeDelete(IndexInfrastructure.getIndexRootDir(name));
IndexingStamp.rewriteVersion(versionFile, version);
}
@@ -394,8 +397,14 @@ public class FileBasedIndexImpl extends FileBasedIndex {
throws IOException {
MapIndexStorage<K, V> storage = null;
final ID<K, V> name = extension.getName();
boolean contentHashesEnumeratorOk = false;
for (int attempt = 0; attempt < 2; attempt++) {
try {
if (extension.hasSnapshotMapping()) {
ContentHashesSupport.initContentHashesEnumerator();
contentHashesEnumeratorOk = true;
}
storage = new MapIndexStorage<K, V>(
IndexInfrastructure.getStorageFile(name),
extension.getKeyDescriptor(),
@@ -443,6 +452,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
}
catch (Exception e) {
LOG.info(e);
boolean instantiatedStorage = storage != null;
try {
if (storage != null) storage.close();
storage = null;
@@ -450,12 +460,22 @@ public class FileBasedIndexImpl extends FileBasedIndex {
catch (Exception ignored) {
}
FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
safeDelete(IndexInfrastructure.getIndexRootDir(name));
if (extension.hasSnapshotMapping() && (!contentHashesEnumeratorOk || instantiatedStorage)) {
safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name)); // todo there is possibility of corruption of storage and content hashes
}
IndexingStamp.rewriteVersion(versionFile, version);
}
}
}
private static boolean safeDelete(File dir) {
File directory = FileUtil.findSequentNonexistentFile(dir.getParentFile(), dir.getName(), "");
boolean success = dir.renameTo(directory);
return FileUtil.delete(success ? directory:dir);
}
private static void saveRegisteredIndices(@NotNull Collection<ID<?, ?>> ids) {
final File file = getRegisteredIndicesFile();
try {
@@ -519,7 +539,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
extension.hasSnapshotMapping() && IdIndex.ourSnapshotMappingsEnabled
? createInputsIndexExternalizer(extension, indexId, extension.getKeyDescriptor())
: null;
index = new MapReduceIndex<K, V, FileContent>(indexId, extension.getIndexer(), storage, externalizer);
index = new MapReduceIndex<K, V, FileContent>(indexId, extension.getIndexer(), storage, externalizer, extension.getValueExternalizer());
}
index.setInputIdToDataKeysIndex(new Factory<PersistentHashMap<Integer, Collection<K>>>() {
@Override
@@ -1620,7 +1640,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
indicesToDrop.remove(key.toString());
}
for (String s : indicesToDrop) {
FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
safeDelete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
}
}
@@ -1715,7 +1735,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
byte[] hash;
try {
currentBytes = content.getBytes();
hash = fileType.isBinary() ? null:ContentHashesSupport.calcContentHashWithFileType(currentBytes, fileType);
hash = fileType.isBinary() || !IdIndex.ourSnapshotMappingsEnabled ? null:ContentHashesSupport.calcContentHashWithFileType(currentBytes, fileType);
}
catch (IOException e) {
currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY;
@@ -36,6 +36,7 @@ import java.util.Locale;
public class IndexInfrastructure {
private static final boolean ourUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
private static final String STUB_VERSIONS = ".versions";
private static final String PERSISTENT_INDEX_DIRECTORY_NAME = ".persistent";
private IndexInfrastructure() {
}
@@ -60,14 +61,35 @@ public class IndexInfrastructure {
return getIndexDirectory(indexName, false);
}
public static File getPersistentIndexRoot() {
File indexDir = new File(PathManager.getIndexRoot() + File.separator + PERSISTENT_INDEX_DIRECTORY_NAME);
indexDir.mkdirs();
return indexDir;
}
@NotNull
public static File getPersistentIndexRootDir(@NotNull ID<?, ?> indexName) {
return getIndexDirectory(indexName, false, PERSISTENT_INDEX_DIRECTORY_NAME);
}
@NotNull
private static File getIndexDirectory(@NotNull ID<?, ?> indexName, boolean forVersion) {
return getIndexDirectory(indexName, forVersion, "");
}
@NotNull
private static File getIndexDirectory(@NotNull ID<?, ?> indexName, boolean forVersion, String relativePath) {
final String dirName = indexName.toString().toLowerCase(Locale.US);
// store StubIndices under StubUpdating index' root to ensure they are deleted
// when StubUpdatingIndex version is changed
final File indexDir = indexName instanceof StubIndexKey
? new File(getIndexRootDir(StubUpdatingIndex.INDEX_ID), forVersion ? STUB_VERSIONS : dirName)
: new File(PathManager.getIndexRoot(), dirName);
File indexDir;
if (indexName instanceof StubIndexKey) {
// store StubIndices under StubUpdating index' root to ensure they are deleted
// when StubUpdatingIndex version is changed
indexDir = new File(getIndexDirectory(StubUpdatingIndex.INDEX_ID, false, relativePath), forVersion ? STUB_VERSIONS : dirName);
} else {
if (relativePath.length() > 0) relativePath = File.separator + relativePath;
indexDir = new File(PathManager.getIndexRoot() + relativePath, dirName);
}
indexDir.mkdirs();
return indexDir;
}
@@ -19,21 +19,22 @@ package com.intellij.util.indexing;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.io.FileUtil;
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.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.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.io.*;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -48,10 +49,12 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private final DataIndexer<Key, Value, Input> myIndexer;
@NotNull protected final IndexStorage<Key, Value> myStorage;
private final boolean myHasSnapshotMapping;
private final DataExternalizer<Value> myValueExternalizer;
private final DataExternalizer<Collection<Key>> mySnapshotIndexExternalizer;
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
private PersistentHashMap<Integer, Collection<Key>> mySnapshotMapping;
private final PersistentHashMap<Integer, ByteSequence> myContents;
private PersistentHashMap<Integer, Integer> myInputsSnapshotMapping;
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
@@ -60,19 +63,34 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
DataIndexer<Key, Value, Input> indexer,
@NotNull IndexStorage<Key, Value> storage) {
this(indexId, indexer, storage, null);
@NotNull IndexStorage<Key, Value> storage) throws IOException {
this(indexId, indexer, storage, null, null);
}
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
DataIndexer<Key, Value, Input> indexer,
@NotNull IndexStorage<Key, Value> storage,
DataExternalizer<Collection<Key>> snapshotIndexExternalizer) {
DataExternalizer<Collection<Key>> snapshotIndexExternalizer,
DataExternalizer<Value> valueDataExternalizer) throws IOException {
myIndexId = indexId;
myIndexer = indexer;
myStorage = storage;
myHasSnapshotMapping = snapshotIndexExternalizer != null;
mySnapshotIndexExternalizer = snapshotIndexExternalizer;
myValueExternalizer = valueDataExternalizer;
final File saved = myHasSnapshotMapping && myIndexId != null ? new File(IndexInfrastructure.getPersistentIndexRootDir(myIndexId), "values") : null;
if (saved != null) {
try {
myContents = new PersistentHashMap<Integer, ByteSequence>(saved, EnumeratorIntegerDescriptor.INSTANCE, ByteSequenceDataExternalizer.INSTANCE);
} catch (IOException ex) {
IOUtil.deleteAllFilesStartingWith(saved);
throw ex;
}
} else {
myContents = null;
}
}
@NotNull
@@ -93,10 +111,6 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
cleanMapping(myInputsSnapshotMapping);
myInputsSnapshotMapping = createInputSnapshotMapping();
}
if (mySnapshotMapping != null) {
cleanMapping(mySnapshotMapping);
mySnapshotMapping = createSnapshotMappingIndex();
}
}
catch (StorageException e) {
LOG.error(e);
@@ -112,17 +126,19 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private PersistentHashMap<Integer, Integer> createInputSnapshotMapping() throws IOException {
assert myIndexId != null;
final File fileIdToHashIdFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "fileIdToHashId");
return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<Integer, Integer>, IOException>() {
@Override
public PersistentHashMap<Integer, Integer> compute() throws IOException {
return new PersistentHashMap<Integer, Integer>(fileIdToHashIdFile, EnumeratorIntegerDescriptor.INSTANCE, EnumeratorIntegerDescriptor.INSTANCE, 4096) {
@Override
protected boolean wantCompactIntegralValues() {
return true;
}
};
}
}, fileIdToHashIdFile);
try {
return new PersistentHashMap<Integer, Integer>(fileIdToHashIdFile, EnumeratorIntegerDescriptor.INSTANCE,
EnumeratorIntegerDescriptor.INSTANCE, 4096) {
@Override
protected boolean wantCompactIntegralValues() {
return true;
}
};
}
catch (IOException ex) {
IOUtil.deleteAllFilesStartingWith(fileIdToHashIdFile);
throw ex;
}
}
private static void cleanMapping(@NotNull PersistentHashMap<?, ?> index) {
@@ -142,7 +158,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
getReadLock().lock();
doForce(myInputsIndex);
doForce(myInputsSnapshotMapping);
doForce(mySnapshotMapping);
doForce(myContents);
myStorage.flush();
}
catch (IOException e) {
@@ -179,7 +195,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
finally {
doClose(myInputsIndex);
doClose(myInputsSnapshotMapping);
doClose(mySnapshotMapping);
doClose(myContents);
}
}
catch (StorageException e) {
@@ -242,22 +258,10 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
myInputsIndexFactory = factory;
if (myHasSnapshotMapping) {
myInputsSnapshotMapping = createInputSnapshotMapping();
mySnapshotMapping = createSnapshotMappingIndex();
}
myInputsIndex = createInputsIndex();
}
private PersistentHashMap<Integer, Collection<Key>> createSnapshotMappingIndex() throws IOException {
assert myIndexId != null;
final File hashIdToKeysFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "hashIdToKeys");
return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<Integer, Collection<Key>>, IOException>() {
@Override
public PersistentHashMap<Integer, Collection<Key>> compute() throws IOException {
return new PersistentHashMap<Integer, Collection<Key>>(hashIdToKeysFile, EnumeratorIntegerDescriptor.INSTANCE, mySnapshotIndexExternalizer);
}
}, hashIdToKeysFile);
}
@Nullable
private PersistentHashMap<Integer, Collection<Key>> createInputsIndex() throws IOException {
Factory<PersistentHashMap<Integer, Collection<Key>>> factory = myInputsIndexFactory;
@@ -275,40 +279,64 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
return null;
}
private static final boolean doReadSavedPersistentData = SystemProperties.getBooleanProperty("idea.read.saved.persistent.index", false);
@NotNull
@Override
public final Computable<Boolean> update(final int inputId, @Nullable Input content) {
final boolean weProcessPhysicalContent = content == null ||
(content instanceof FileContent &&
((FileContent)content).getUserData(FileBasedIndexImpl.ourPhysicalContentKey) != null);
final Map<Key, Value> data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
Map<Key, Value> data = null;
boolean havePersistentData = false;
Integer hashId = null;
if (myContents != null && weProcessPhysicalContent && content != null) {
try {
hashId = getHashOfContent((FileContent)content);
if (doReadSavedPersistentData) {
ByteSequence bytes = myContents.get(hashId);
if (bytes != null) {
data = deserializeSavedPersistentData(bytes);
havePersistentData = true;
}
} else {
havePersistentData = myContents.containsMapping(hashId);
}
} catch (IOException ex) {
// todo:
throw new RuntimeException(ex);
}
}
if (data == null) data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
if (hashId != null && !havePersistentData && data.size() > 0) {
savePersistentData(data, hashId);
}
ProgressManager.checkCanceled();
final NotNullComputable<Collection<Key>> oldKeysGetter;
final int savedInputId;
boolean weProcessPhysicalContent = content == null ||
(content instanceof FileContent &&
((FileContent)content).getUserData(FileBasedIndexImpl.ourPhysicalContentKey) != null);
if (myHasSnapshotMapping && weProcessPhysicalContent) {
try { // optimistically (out of index update write section) read current snapshot keys for file
final Integer hashId = myInputsSnapshotMapping.get(inputId);
final Collection<Key> keys = hashId != null ? mySnapshotMapping.get(hashId): null;
try {
oldKeysGetter = new NotNullComputable<Collection<Key>>() {
@NotNull
@Override
public Collection<Key> compute() {
@NotNull
@Override
public Collection<Key> compute() {
try {
Integer currentHashId = myInputsSnapshotMapping.get(inputId);
Collection<Key> currentKeys;
if ((currentHashId == null && hashId == null) || (currentHashId != null && currentHashId.equals(hashId))) {
currentKeys = keys;
} else { // optimistic reading file's current keys failed
currentKeys = currentHashId != null ? mySnapshotMapping.get(currentHashId): null;
if (currentHashId != null) {
ByteSequence byteSequence = myContents.get(currentHashId);
currentKeys = byteSequence != null ? deserializeSavedPersistentData(byteSequence).keySet() : Collections.<Key>emptyList();
}
else {
currentKeys = Collections.emptyList();
}
return currentKeys == null ? Collections.<Key>emptyList() : currentKeys;
return currentKeys;
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -316,22 +344,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
};
if (content instanceof FileContent) {
FileContent fileContent = (FileContent)content;
Integer previouslyCalculatedContentHashId = fileContent.getUserData(ourSavedContentHashIdKey);
if (previouslyCalculatedContentHashId == null) {
byte[] hash = fileContent instanceof FileContentImpl ? ((FileContentImpl)fileContent).getHash():null;
if (hash == null) {
previouslyCalculatedContentHashId = ContentHashesSupport.calcContentHashIdWithFileType(fileContent.getContent(), fileContent.getFileType());
} else {
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
}
fileContent.putUserData(ourSavedContentHashIdKey, previouslyCalculatedContentHashId);
}
savedInputId = previouslyCalculatedContentHashId;
if (!mySnapshotMapping.containsMapping(savedInputId)) { // save current snapshot keys out of index update write section
mySnapshotMapping.put(savedInputId, data.keySet());
}
savedInputId = getHashOfContent((FileContent)content);
} else {
savedInputId = NULL_MAPPING;
}
@@ -356,6 +369,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
}
// do not depend on content!
final Map<Key, Value> finalData = data;
return new Computable<Boolean>() {
@Override
public Boolean compute() {
@@ -364,7 +378,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
@Override
public void run() {
try {
updateWithMap(inputId, savedInputId, data, oldKeysGetter);
updateWithMap(inputId, savedInputId, finalData, oldKeysGetter);
}
catch (StorageException ex) {
exRef.set(ex);
@@ -383,6 +397,74 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
};
}
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);
if (pairs == 0) return Collections.emptyMap();
Map<Key, Value> result = new THashMap<Key, Value>(pairs);
while (stream.available() > 0) {
Value value = myValueExternalizer.read(stream);
Collection<Key> keys = mySnapshotIndexExternalizer.read(stream);
for(Key k:keys) result.put(k, value);
}
return result;
}
private static Integer getHashOfContent(FileContent content) throws IOException {
Integer previouslyCalculatedContentHashId = content.getUserData(ourSavedContentHashIdKey);
if (previouslyCalculatedContentHashId == null) {
byte[] hash = content instanceof FileContentImpl ? ((FileContentImpl)content).getHash():null;
if (hash == null) {
previouslyCalculatedContentHashId = ContentHashesSupport
.calcContentHashIdWithFileType(content.getContent(), content.getFileType());
} else {
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
}
content.putUserData(ourSavedContentHashIdKey, previouslyCalculatedContentHashId);
}
return previouslyCalculatedContentHashId;
}
private static final ThreadLocalCachedByteArray ourSpareByteArray = new ThreadLocalCachedByteArray();
private void savePersistentData(Map<Key, Value> data, int id) {
try {
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(ourSpareByteArray.getBuffer(4 * data.size()));
DataOutputStream stream = new DataOutputStream(out);
int size = data.size();
DataInputOutputUtil.writeINT(stream, size);
if (size > 0) {
THashMap<Value, List<Key>> values = new THashMap<Value, List<Key>>();
List<Key> keysForNullValue = null;
for (Map.Entry<Key, Value> e : data.entrySet()) {
Value value = e.getValue();
List<Key> keys = value != null ? values.get(value):keysForNullValue;
if (keys == null) {
if (value != null) values.put(value, keys = new SmartList<Key>());
else keys = keysForNullValue = new SmartList<Key>();
}
keys.add(e.getKey());
}
if (keysForNullValue != null) {
myValueExternalizer.save(stream, null);
mySnapshotIndexExternalizer.save(stream, keysForNullValue);
}
for(Value value:values.keySet()) {
myValueExternalizer.save(stream, value);
mySnapshotIndexExternalizer.save(stream, values.get(value));
}
}
myContents.put(id, new ByteSequence(out.getInternalBuffer(), 0, out.size()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private static final com.intellij.openapi.util.Key<Integer> ourSavedContentHashIdKey = com.intellij.openapi.util.Key.create("saved.content.hash.id");
protected void updateWithMap(final int inputId,
@@ -62,7 +62,7 @@ import java.util.*;
},
storageChooser = HttpConfigurable.StorageChooser.class
)
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ApplicationComponent, JDOMExternalizable,
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ApplicationComponent,
ExportableApplicationComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.net.HttpConfigurable");
public boolean PROXY_TYPE_IS_SOCKS = false;
@@ -98,6 +98,7 @@ public class HttpConfigurable implements PersistentStateComponent<HttpConfigurab
@Override
public HttpConfigurable getState() {
CommonProxy.isInstalledAssertion();
final HttpConfigurable state = new HttpConfigurable();
XmlSerializerUtil.copyBean(this, state);
if (!KEEP_PROXY_PASSWORD) {
@@ -306,15 +307,14 @@ public class HttpConfigurable implements PersistentStateComponent<HttpConfigurab
}
}
//these methods are preserved for compatibility
@Override
//these methods are preserved for compatibility with com.intellij.openapi.project.impl.IdeaServerSettings
@Deprecated
public void readExternal(Element element) throws InvalidDataException {
loadState(XmlSerializer.deserialize(element, HttpConfigurable.class));
}
@Override
@Deprecated
public void writeExternal(Element element) throws WriteExternalException {
CommonProxy.isInstalledAssertion();
XmlSerializer.serializeInto(getState(), element);
if (USE_PROXY_PAC && USE_HTTP_PROXY && ! ApplicationManager.getApplication().isDisposed()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -21,6 +21,7 @@ import com.intellij.openapi.components.StorageId;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.util.xmlb.Accessor;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
@@ -92,7 +93,11 @@ class DefaultStateSerializer {
//assert mergeInto == null;
return (T)stateElement;
}
else if (JDOMExternalizable.class.isAssignableFrom(stateClass) && mergeInto == null) {
else if (JDOMExternalizable.class.isAssignableFrom(stateClass)) {
if (mergeInto != null) {
String elementText = JDOMUtil.writeElement(stateElement, "\n");
LOG.error("State is " + stateClass.getName() + ", merge into is " + mergeInto.toString() + ", state element text is " + elementText);
}
try {
final T t = stateClass.newInstance();
try {
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 Bas Leijdekkers
* Copyright 2011-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -227,12 +227,23 @@ public class MismatchedStringBuilderQueryUpdateInspection extends BaseInspection
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
if (updated) {
return;
}
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
checkReferenceExpression(expression.getMethodExpression());
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
if (updated) {
return;
}
super.visitMethodReferenceExpression(expression);
checkReferenceExpression(expression);
}
private void checkReferenceExpression(PsiReferenceExpression methodExpression) {
final String name = methodExpression.getReferenceName();
if (!updateNames.contains(name)) {
return;
@@ -7,7 +7,7 @@ public class MismatchedStringBuilderQueryUpdate {
b.append("");
System.out.println("" + b + "");
final StringBuilder c = new StringBuilder();
final StringBuilder <warning descr="Contents of StringBuilder 'c' are updated, but never queried">c</warning> = new StringBuilder();
c.append(' ');
}
@@ -17,4 +17,17 @@ public class MismatchedStringBuilderQueryUpdate {
sb.append("abc");
return sb.reverse();
}
void indexedList(List<String> list) {
StringBuilder stringBuilder = new StringBuilder(); // <--- false warning here
list.forEach(stringBuilder::append);
System.out.println(stringBuilder.toString());
}
}
interface List<T> {
default void forEach(Consumer<? super T> action) {
}
}
interface Consumer<T> {
void accept(T t);
}
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>MismatchedStringBuilderQueryUpdate.java</file>
<line>10</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched query and update of StringBuilder</problem_class>
<description>Contents of StringBuilder &lt;code&gt;c&lt;/code&gt; are updated, but never queried #loc</description>
</problem>
</problems>
@@ -1,10 +1,16 @@
package com.siyeh.ig.bugs;
import com.siyeh.ig.IGInspectionTestCase;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
public class MismatchedStringBuilderQueryUpdateInspectionTest extends IGInspectionTestCase {
public class MismatchedStringBuilderQueryUpdateInspectionTest extends LightInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/bugs/mismatched_string_builder_query_update", new MismatchedStringBuilderQueryUpdateInspection());
public void testMismatchedStringBuilderQueryUpdate() throws Exception {
doTest();
}
@Override
protected InspectionProfileEntry getInspection() {
return new MismatchedStringBuilderQueryUpdateInspection();
}
}
@@ -26,9 +26,12 @@ import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.xml.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.DomFileElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.devkit.DevKitBundle;
import org.jetbrains.idea.devkit.dom.Dependency;
import org.jetbrains.idea.devkit.dom.IdeaPlugin;
import org.jetbrains.idea.devkit.module.PluginModuleType;
import org.jetbrains.idea.devkit.util.ActionType;
import org.jetbrains.idea.devkit.util.ComponentType;
@@ -62,7 +65,8 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
if (PluginModuleType.isOfType(module)) {
return checkModule(module, psiClass, null, includeActions);
} else {
}
else {
Set<PsiClass> types = null;
final List<Module> modules = PluginModuleType.getCandidateModules(module);
for (Module m : modules) {
@@ -78,20 +82,26 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
if (!DescriptorUtil.isPluginXml(pluginXml)) return types;
assert pluginXml != null;
final XmlDocument document = pluginXml.getDocument();
assert document != null;
final XmlTag rootTag = document.getRootTag();
assert rootTag != null;
final String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName != null) {
final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass, types);
DescriptorUtil.processComponents(rootTag, finder);
// "main" plugin.xml
processPluginXml(pluginXml, finder, includeActions);
if (includeActions) {
DescriptorUtil.processActions(rootTag, finder);
// <depends> plugin.xml files
final VirtualFile pluginXmlDirectory = pluginXml.getVirtualFile().getParent();
final DomFileElement<IdeaPlugin> fileElement = DescriptorUtil.getIdeaPlugin(pluginXml);
for (Dependency dependency : fileElement.getRootElement().getDependencies()) {
final String configFile = dependency.getConfigFile().getValue();
if (configFile != null) {
final VirtualFile depVirtualFile = pluginXmlDirectory.findChild(configFile);
if (depVirtualFile == null) continue;
final PsiFile depPluginXml = PsiManager.getInstance(module.getProject()).findFile(depVirtualFile);
if (DescriptorUtil.isPluginXml(depPluginXml)) {
processPluginXml((XmlFile)depPluginXml, finder, includeActions);
}
}
}
types = finder.getTypes();
@@ -100,6 +110,18 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
return types;
}
private static void processPluginXml(XmlFile xmlFile, RegistrationTypeFinder finder, boolean includeActions) {
final XmlDocument document = xmlFile.getDocument();
if (document == null) return;
final XmlTag rootTag = document.getRootTag();
if (rootTag == null) return;
DescriptorUtil.processComponents(rootTag, finder);
if (includeActions) {
DescriptorUtil.processActions(rootTag, finder);
}
}
@Nullable
protected static PsiElement getAttValueToken(@NotNull XmlAttribute attribute) {
final XmlAttributeValue valueElement = attribute.getValueElement();
@@ -132,13 +154,14 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
return false;
}
static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor {
private static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor {
private Set<PsiClass> myTypes;
private final String myQualifiedName;
private final PsiManager myManager;
private final GlobalSearchScope myScope;
public RegistrationTypeFinder(PsiClass psiClass, Set<PsiClass> types) {
private RegistrationTypeFinder(PsiClass psiClass, Set<PsiClass> types) {
myTypes = types;
myQualifiedName = psiClass.getQualifiedName();
myManager = psiClass.getManager();
+1 -1
View File
@@ -87,7 +87,7 @@ public class DescriptorUtil {
return getIdeaPlugin((XmlFile)file) != null;
}
private static DomFileElement<IdeaPlugin> getIdeaPlugin(XmlFile file) {
public static DomFileElement<IdeaPlugin> getIdeaPlugin(XmlFile file) {
return DomManager.getDomManager(file.getProject()).getFileElement(file, IdeaPlugin.class);
}
}
@@ -0,0 +1,6 @@
<idea-plugin>
<actions>
<action id="registeredAction" class="RegisteredAction"/>
<action id="registeredInnerAction" class="RegisteredAction.InnerAction"/>
</actions>
</idea-plugin>
@@ -0,0 +1,5 @@
<idea-plugin>
<!-- registeredActionInOptionalPluginDescriptor-optional-plugin.xml -->
<depends optional="true" config-file="optional-plugin.xml"/>
<depends optional="true" config-file="optional-plugin.xml"/>
</idea-plugin>
@@ -67,6 +67,14 @@ public class ComponentNotRegisteredInspectionTest extends LightCodeInsightFixtur
myFixture.testHighlighting("RegisteredAction.java");
}
public void testRegisteredActionInOptionalPluginDescriptor() {
setPluginXml("registeredActionInOptionalPluginDescriptor-plugin.xml");
myFixture.copyFileToProject("registeredActionInOptionalPluginDescriptor-optional-plugin.xml",
"META-INF/optional-plugin.xml");
myFixture.testHighlighting("RegisteredAction.java");
}
public void testUnregisteredAction() {
setPluginXml("unregisteredAction-plugin.xml");
myFixture.testHighlighting("UnregisteredAction.java");