(instead of numerous stub index locks) use stub_updating_index's lock for processing stubs, flushing, clearing, disposing

as side effect accessing stub indices during processing other stub indices is allowed
This commit is contained in:
Maxim.Mossienko
2017-05-14 01:36:12 +02:00
parent 29ee694a66
commit fa12df795c
5 changed files with 107 additions and 113 deletions
@@ -536,7 +536,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
}
assertTrue(foundClass[0])
assertTrue(!foundMethod[0])
assertTrue(foundMethod[0]) // allow access stub index processing other index
def foundClassProcessAll = [false]
def foundClassStub = [false]
@@ -39,10 +39,7 @@ import com.intellij.util.Processors;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.*;
import com.intellij.util.indexing.impl.IndexStorage;
import com.intellij.util.indexing.impl.InputDataDiffBuilder;
import com.intellij.util.indexing.impl.MapInputDataDiffBuilder;
import com.intellij.util.indexing.impl.UpdateData;
import com.intellij.util.indexing.impl.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.KeyDescriptor;
@@ -59,7 +56,7 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@State(name = "FileBasedIndex", storages = @Storage(value = "stubIndex.xml", roamingType = RoamingType.DISABLED))
public class StubIndexImpl extends StubIndex implements PersistentStateComponent<StubIndexState>, ApplicationComponent {
@@ -214,9 +211,7 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
if (!myInitialized) {
return;
}
AsyncState state = getAsyncState();
for (StubIndexKey key : getAllStubIndexKeys()) {
final MyIndex<?> index = state.myIndices.get(key);
for (MyIndex<?> index : getAsyncState().myIndices.values()) {
index.flush();
}
}
@@ -344,27 +339,29 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
@Nullable final GlobalSearchScope scope,
@NotNull StubIdListContainerAction action) {
final FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance();
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(StubUpdatingIndex.INDEX_ID);
fileBasedIndex.ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope);
ID<Integer, SerializedStubTree> stubUpdatingIndexId = StubUpdatingIndex.INDEX_ID;
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(stubUpdatingIndexId);
fileBasedIndex.ensureUpToDate(stubUpdatingIndexId, project, scope);
final MyIndex<Key> index = (MyIndex<Key>)getAsyncState().myIndices.get(indexKey);
UpdatableIndex<Integer, SerializedStubTree, FileContent> stubUpdatingIndex = fileBasedIndex.getIndex(stubUpdatingIndexId);
try {
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(indexKey);
myAccessValidator.checkAccessingIndexDuringOtherIndexProcessing(stubUpdatingIndexId);
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();
stubUpdatingIndex.getReadLock().lock();
myAccessValidator.startedProcessingActivityForIndex(indexKey);
myAccessValidator.startedProcessingActivityForIndex(stubUpdatingIndexId);
return index.getData(key).forEach(action);
}
finally {
myAccessValidator.stoppedProcessingActivityForIndex(indexKey);
index.getReadLock().unlock();
myAccessValidator.stoppedProcessingActivityForIndex(stubUpdatingIndexId);
stubUpdatingIndex.getReadLock().unlock();
FileBasedIndexImpl.enableUpToDateCheckForCurrentThread();
}
}
@@ -505,19 +502,21 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
}
public void cleanupMemoryStorage() {
for (UpdatableIndex index : getAsyncState().myIndices.values()) {
final IndexStorage indexStorage = ((VfsAwareMapReduceIndex)index).getStorage();
index.getWriteLock().lock();
try {
UpdatableIndex<Integer, SerializedStubTree, FileContent> stubUpdatingIndex =
((FileBasedIndexImpl)FileBasedIndex.getInstance()).getIndex(StubUpdatingIndex.INDEX_ID);
stubUpdatingIndex.getWriteLock().lock();
try {
for (UpdatableIndex index : getAsyncState().myIndices.values()) {
final IndexStorage indexStorage = ((VfsAwareMapReduceIndex)index).getStorage();
((MemoryIndexStorage)indexStorage).clearMemoryMap();
}
finally {
index.getWriteLock().unlock();
}
}
finally {
stubUpdatingIndex.getWriteLock().unlock();
}
}
public void clearAllIndices() {
for (UpdatableIndex index : getAsyncState().myIndices.values()) {
try {
@@ -561,14 +560,6 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
myPreviouslyRegistered = state;
}
public final Lock getWriteLock(StubIndexKey indexKey) {
return getAsyncState().myIndices.get(indexKey).getWriteLock();
}
Collection<StubIndexKey> getAllStubIndexKeys() {
return Collections.unmodifiableCollection(getAsyncState().myIndices.keySet());
}
public <K> void updateIndex(@NotNull StubIndexKey key,
int fileId,
@NotNull final Map<K, StubIdList> oldValues,
@@ -586,6 +577,12 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
}
private static class MyIndex<K> extends VfsAwareMapReduceIndex<K, StubIdList, Void> {
@NotNull
@Override
protected ReentrantReadWriteLock createLock() {
UpdatableIndex<?, ?, FileContent> index = ((FileBasedIndexImpl)FileBasedIndex.getInstance()).getIndex(StubUpdatingIndex.INDEX_ID);
return ((MapReduceIndex)index).getLock();
}
public MyIndex(IndexExtension<K, StubIdList, Void> extension, IndexStorage<K, StubIdList> storage) throws IOException {
super(extension, storage);
@@ -441,13 +441,13 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
}
@Override
public void flush() throws StorageException {
protected void doFlush() throws IOException, StorageException {
final StubIndexImpl stubIndex = getStubIndex();
try {
stubIndex.flush();
}
finally {
super.flush();
super.doFlush();
}
}
@@ -458,36 +458,22 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
StubUpdatingData stubUpdatingData = (StubUpdatingData)updateData;
final Map<StubIndexKey, Map<Object, StubIdList>> newStubIndicesValueMap = stubUpdatingData.getNewStubIndicesValueMap();
final StubIndexImpl stubIndex = getStubIndex();
final Collection<StubIndexKey> allStubIndices = stubIndex.getAllStubIndexKeys();
try {
// first write-lock affected stub indices to avoid deadlocks
for (StubIndexKey key : allStubIndices) {
stubIndex.getWriteLock(key).lock();
}
getWriteLock().lock();
try {
getWriteLock().lock();
super.updateWithMap(inputId, updateData);
super.updateWithMap(inputId, updateData);
final Map<StubIndexKey, Map<Object, StubIdList>> previousStubIndicesValueMap = stubUpdatingData.getOldStubIndicesValueMap();
final Map<StubIndexKey, Map<Object, StubIdList>> previousStubIndicesValueMap = stubUpdatingData.getOldStubIndicesValueMap();
updateStubIndices(
getAffectedIndices(previousStubIndicesValueMap, newStubIndicesValueMap),
inputId,
previousStubIndicesValueMap,
newStubIndicesValueMap
);
}
finally {
getWriteLock().unlock();
}
updateStubIndices(
getAffectedIndices(previousStubIndicesValueMap, newStubIndicesValueMap),
inputId,
previousStubIndicesValueMap,
newStubIndicesValueMap
);
}
finally {
for (StubIndexKey key : allStubIndices) {
stubIndex.getWriteLock(key).unlock();
}
getWriteLock().unlock();
}
}
@@ -509,34 +495,19 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
}
@Override
public void clear() throws StorageException {
protected void doClear() throws StorageException, IOException {
final StubIndexImpl stubIndex = StubIndexImpl.getInstanceOrInvalidate();
final Collection<StubIndexKey> allStubIndexKeys = stubIndex != null? stubIndex.getAllStubIndexKeys() : Collections.emptyList();
try {
for (StubIndexKey key : allStubIndexKeys) {
//noinspection ConstantConditions
stubIndex.getWriteLock(key).lock();
}
getWriteLock().lock();
if (stubIndex != null) {
stubIndex.clearAllIndices();
}
myStubVersionMap.clear();
super.clear();
}
finally {
getWriteLock().unlock();
for (StubIndexKey key : allStubIndexKeys) {
//noinspection ConstantConditions
stubIndex.getWriteLock(key).unlock();
}
if (stubIndex != null) {
stubIndex.clearAllIndices();
}
myStubVersionMap.clear();
super.doClear();
}
@Override
public void dispose() {
protected void doDispose() throws StorageException {
try {
super.dispose();
super.doDispose();
}
finally {
getStubIndex().dispose();
@@ -57,7 +57,7 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
}
private final AtomicBoolean myInMemoryMode = new AtomicBoolean();
private final TIntObjectHashMap<Collection<Key>> myInMemoryKeys = new TIntObjectHashMap<Collection<Key>>();
private final TIntObjectHashMap<Collection<Key>> myInMemoryKeys = new TIntObjectHashMap<>();
private final SnapshotInputMappings<Key, Value, Input> mySnapshotInputMappings;
public VfsAwareMapReduceIndex(@NotNull IndexExtension<Key, Value, Input> extension,
@@ -179,30 +179,35 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
}
@Override
public void clear() throws StorageException {
super.clear();
if (mySnapshotInputMappings != null) try {
mySnapshotInputMappings.clear();
}
catch (IOException e) {
LOG.error(e);
protected void doClear() throws StorageException, IOException {
super.doClear();
if (mySnapshotInputMappings != null) {
try {
mySnapshotInputMappings.clear();
}
catch (IOException e) {
LOG.error(e);
}
}
}
@Override
public void flush() throws StorageException {
super.flush();
protected void doFlush() throws IOException, StorageException {
super.doFlush();
if (mySnapshotInputMappings != null) mySnapshotInputMappings.flush();
}
@Override
public void dispose() {
super.dispose();
if (mySnapshotInputMappings != null) try {
mySnapshotInputMappings.close();
}
catch (IOException e) {
LOG.error(e);
protected void doDispose() throws StorageException {
super.doDispose();
if (mySnapshotInputMappings != null) {
try {
mySnapshotInputMappings.close();
}
catch (IOException e) {
LOG.error(e);
}
}
}
@@ -52,7 +52,7 @@ public abstract class MapReduceIndex<Key,Value, Input> implements InvertedIndex<
protected final ForwardIndex<Key, Value> myForwardIndex;
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock myLock = createLock();
private volatile boolean myDisposed;
private final LowMemoryWatcher myLowMemoryFlusher = LowMemoryWatcher.register(new Runnable() {
@@ -91,12 +91,20 @@ public abstract class MapReduceIndex<Key,Value, Input> implements InvertedIndex<
return myStorage;
}
@NotNull
protected ReentrantReadWriteLock createLock() {
return new ReentrantReadWriteLock();
}
public final ReentrantReadWriteLock getLock() {
return myLock;
}
@Override
public void clear() throws StorageException {
try {
getWriteLock().lock();
myStorage.clear();
if (myForwardIndex != null) myForwardIndex.clear();
doClear();
}
catch (StorageException e) {
LOG.error(e);
@@ -109,12 +117,16 @@ public abstract class MapReduceIndex<Key,Value, Input> implements InvertedIndex<
}
}
protected void doClear() throws StorageException, IOException {
myStorage.clear();
if (myForwardIndex != null) myForwardIndex.clear();
}
@Override
public void flush() throws StorageException{
try {
getReadLock().lock();
if (myForwardIndex != null) myForwardIndex.flush();
myStorage.flush();
doFlush();
}
catch (IOException e) {
throw new StorageException(e);
@@ -133,23 +145,18 @@ public abstract class MapReduceIndex<Key,Value, Input> implements InvertedIndex<
}
}
protected void doFlush() throws IOException, StorageException {
if (myForwardIndex != null) myForwardIndex.flush();
myStorage.flush();
}
@Override
public void dispose() {
myLowMemoryFlusher.stop();
final Lock lock = getWriteLock();
try {
lock.lock();
try {
myStorage.close();
}
finally {
try {
if (myForwardIndex != null) myForwardIndex.close();
}
catch (IOException e) {
LOG.error(e);
}
}
doDispose();
}
catch (StorageException e) {
LOG.error(e);
@@ -160,6 +167,20 @@ public abstract class MapReduceIndex<Key,Value, Input> implements InvertedIndex<
}
}
protected void doDispose() throws StorageException {
try {
myStorage.close();
}
finally {
try {
if (myForwardIndex != null) myForwardIndex.close();
}
catch (IOException e) {
LOG.error(e);
}
}
}
@NotNull
public final Lock getReadLock() {
return myLock.readLock();