mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
report nested index access
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.index
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.command.impl.CurrentEditorProvider
|
||||
import com.intellij.openapi.command.impl.UndoManagerImpl
|
||||
@@ -33,20 +32,27 @@ import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import com.intellij.psi.impl.PsiManagerEx
|
||||
import com.intellij.psi.impl.cache.impl.id.IdIndex
|
||||
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
|
||||
import com.intellij.psi.impl.file.impl.FileManagerImpl
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect
|
||||
import com.intellij.psi.impl.source.PsiFileWithStubSupport
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.PsiSearchHelper
|
||||
import com.intellij.psi.stubs.SerializedStubTree
|
||||
import com.intellij.psi.stubs.StubIndex
|
||||
import com.intellij.psi.stubs.StubUpdatingIndex
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.SkipSlowTestLocally
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
|
||||
import com.intellij.util.Processor
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import com.intellij.util.indexing.MapIndexStorage
|
||||
import com.intellij.util.indexing.StorageException
|
||||
import com.intellij.util.io.*
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* @since Dec 12, 2007
|
||||
@@ -425,4 +431,69 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
assertNotNull(stubTree)
|
||||
assertEquals(stubTreeHash, stubTree.hashCode())
|
||||
}
|
||||
|
||||
public void "test report using index from other index"() throws IOException {
|
||||
def vfile = myFixture.addClass("class Foo { void bar() {} }").getContainingFile().getVirtualFile();
|
||||
def scope = GlobalSearchScope.allScope(project)
|
||||
def foundClass = [false];
|
||||
def foundMethod = [false];
|
||||
|
||||
try {
|
||||
StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_SHORT_NAMES, "Foo", project, scope,
|
||||
PsiClass.class,
|
||||
new Processor<PsiClass>() {
|
||||
@Override
|
||||
boolean process(PsiClass aClass) {
|
||||
foundClass[0] = true
|
||||
StubIndex.instance.processElements(JavaStubIndexKeys.METHODS, "bar", project, scope,
|
||||
PsiMethod.class,
|
||||
new Processor<PsiMethod>() {
|
||||
@Override
|
||||
boolean process(PsiMethod method) {
|
||||
foundMethod[0] = true;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!(e instanceof RuntimeException)) throw e;
|
||||
}
|
||||
|
||||
assertTrue(foundClass[0])
|
||||
assertTrue(!foundMethod[0])
|
||||
|
||||
def foundId = [false];
|
||||
def foundStub = [false];
|
||||
|
||||
try {
|
||||
FileBasedIndex.instance.
|
||||
processValues(IdIndex.NAME, new IdIndexEntry("Foo", true), null, new FileBasedIndex.ValueProcessor<Integer>() {
|
||||
@Override
|
||||
boolean process(VirtualFile file, Integer value) {
|
||||
foundId[0] = true
|
||||
FileBasedIndex.instance.processValues(
|
||||
StubUpdatingIndex.INDEX_ID,
|
||||
vfile.id,
|
||||
null,
|
||||
new FileBasedIndex.ValueProcessor<SerializedStubTree>() {
|
||||
@Override
|
||||
boolean process(VirtualFile file2, SerializedStubTree value2) {
|
||||
foundStub[0] = true
|
||||
return true
|
||||
}
|
||||
},
|
||||
scope
|
||||
);
|
||||
return true
|
||||
}
|
||||
}, scope)
|
||||
} catch (e) {
|
||||
if (!(e instanceof RuntimeException)) throw e;
|
||||
}
|
||||
|
||||
assertTrue(foundId[0])
|
||||
assertTrue(!foundStub[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
private final TObjectIntHashMap<ID<?, ?>> myIndexIdToVersionMap = new TObjectIntHashMap<ID<?, ?>>();
|
||||
|
||||
private final StubProcessingHelper myStubProcessingHelper;
|
||||
private final IndexAccessValidator myAccessValidator = new IndexAccessValidator();
|
||||
|
||||
private StubIndexState myPreviouslyRegistered;
|
||||
|
||||
@@ -244,14 +245,20 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
final MyIndex<Key> index = (MyIndex<Key>)myIndices.get(indexKey);
|
||||
|
||||
try {
|
||||
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(indexKey);
|
||||
|
||||
try {
|
||||
// disable up-to-date check to avoid locks on attempt to acquire index write lock while holding at the same time the readLock for this index
|
||||
FileBasedIndexImpl.disableUpToDateCheckForCurrentThread();
|
||||
|
||||
index.getReadLock().lock();
|
||||
|
||||
myAccessValidator.startedProcessingActivityForIndex(indexKey);
|
||||
|
||||
return index.getData(key).forEach(action);
|
||||
}
|
||||
finally {
|
||||
myAccessValidator.stoppedProcessingActivityForIndex(indexKey);
|
||||
index.getReadLock().unlock();
|
||||
FileBasedIndexImpl.enableUpToDateCheckForCurrentThread();
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
private volatile int myFilesModCount;
|
||||
private final AtomicInteger myUpdatingFiles = new AtomicInteger();
|
||||
private final Set<Project> myProjectsBeingUpdated = ContainerUtil.newConcurrentSet();
|
||||
private final IndexAccessValidator myAccessValidator = new IndexAccessValidator();
|
||||
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private volatile boolean myInitialized;
|
||||
// need this variable for memory barrier
|
||||
@@ -269,6 +270,8 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void requestReindex(@NotNull final VirtualFile file) {
|
||||
myChangedFilesCollector.invalidateIndices(file, true);
|
||||
@@ -961,11 +964,15 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
//assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries";
|
||||
ensureUpToDate(indexId, project, filter, restrictToFile);
|
||||
|
||||
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(indexId);
|
||||
|
||||
try {
|
||||
index.getReadLock().lock();
|
||||
myAccessValidator.startedProcessingActivityForIndex(indexId);
|
||||
return computable.convert(index);
|
||||
}
|
||||
finally {
|
||||
myAccessValidator.stoppedProcessingActivityForIndex(indexId);
|
||||
index.getReadLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* Created by Maxim.Mossienko on 11/23/2015.
|
||||
*/
|
||||
public class IndexAccessValidator {
|
||||
private final ThreadLocal<ID<?, ?>> ourAlreadyProcessingIndices = new ThreadLocal<ID<?, ?>>();
|
||||
|
||||
public void checkAccessingIndexDuringOtherIndexProcessing(@NotNull ID<?, ?> indexKey) {
|
||||
final ID<?, ?> alreadyProcessingIndex = ourAlreadyProcessingIndices.get();
|
||||
if (alreadyProcessingIndex != null && alreadyProcessingIndex != indexKey) {
|
||||
final String message = MessageFormat.format("Accessing ''{0}'' during processing ''{1}''. Nested different indices processing may cause deadlock",
|
||||
indexKey.toString(),
|
||||
alreadyProcessingIndex.toString());
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message);
|
||||
Logger.getInstance(FileBasedIndexImpl.class).error(message); // RuntimeException to skip rebuild
|
||||
}
|
||||
}
|
||||
|
||||
public void startedProcessingActivityForIndex(ID<?,?> indexId) { ourAlreadyProcessingIndices.set(indexId); }
|
||||
public void stoppedProcessingActivityForIndex(ID<?,?> indexId) { ourAlreadyProcessingIndices.set(null); }
|
||||
}
|
||||
Reference in New Issue
Block a user