diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index 89c069c38fac..f6d6283ef069 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -36,6 +36,7 @@ import java.io.DataOutput; import java.io.File; import java.io.IOException; import java.util.*; +import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; @@ -374,10 +375,14 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe return Collections.unmodifiableCollection(myIndices.keySet()); } - public void updateIndex(StubIndexKey key, int fileId, Map oldValues, Map newValues) { + public void updateIndex(StubIndexKey key, int fileId, final Map oldValues, Map newValues) { try { - MyIndex index = (MyIndex)myIndices.get(key); - index.updateWithMap(fileId, newValues, oldValues.keySet()); + final MyIndex index = (MyIndex)myIndices.get(key); + index.updateWithMap(fileId, newValues, new Callable>() { + public Collection call() throws Exception { + return oldValues.keySet(); + } + }); } catch (StorageException e) { LOG.info(e); @@ -390,14 +395,8 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe super(null, null, storage); } - public void updateWithMap(final int inputId, final Map newData, Collection oldKeys) throws StorageException { - getWriteLock().lock(); - try { - super.updateWithMap(inputId, newData, oldKeys); - } - finally { - getWriteLock().unlock(); - } + public void updateWithMap(final int inputId, final Map newData, Callable> oldKeysGetter) throws StorageException { + super.updateWithMap(inputId, newData, oldKeysGetter); } } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 0e313fccad69..ece49c8244fb 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -32,7 +32,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.*; -import java.util.concurrent.locks.Lock; +import java.util.concurrent.Callable; public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtension { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubUpdatingIndex"); @@ -256,8 +256,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } } - private static void updateStubIndices(final Collection indexKeys, final int inputId, final Map> oldStubTree, - final Map> newStubTree) { + private static void updateStubIndices(final Collection indexKeys, final int inputId, final Map> oldStubTree, final Map> newStubTree) { final StubIndexImpl stubIndex = (StubIndexImpl)StubIndex.getInstance(); for (StubIndexKey key : indexKeys) { final Map oldMap = oldStubTree.get(key); @@ -290,26 +289,29 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } } - protected void updateWithMap(final int inputId, final Map newData, Collection oldKeys) + protected void updateWithMap(final int inputId, final Map newData, Callable> oldKeysGetter) throws StorageException { checkNameStorage(); - Map oldData = readOldData(inputId); - final Map> oldStubTree = getStubTree(oldData); final Map> newStubTree = getStubTree(newData); - final Collection affectedIndices = getAffectedIndices(oldStubTree, newStubTree); final StubIndexImpl stubIndex = (StubIndexImpl)StubIndex.getInstance(); + final Collection allStubIndices = stubIndex.getAllStubIndexKeys(); try { // first write-lock affected stub indices to avoid deadlocks - for (StubIndexKey key : affectedIndices) { + for (StubIndexKey key : allStubIndices) { stubIndex.getWriteLock(key).lock(); } try { getWriteLock().lock(); - super.updateWithMap(inputId, newData, oldKeys); - updateStubIndices(affectedIndices, inputId, oldStubTree, newStubTree); + + final Map oldData = readOldData(inputId); + final Map> oldStubTree = getStubTree(oldData); + + super.updateWithMap(inputId, newData, oldKeysGetter); + + updateStubIndices(getAffectedIndices(oldStubTree, newStubTree), inputId, oldStubTree, newStubTree); } finally { getWriteLock().unlock(); @@ -317,7 +319,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } finally { - for (StubIndexKey key : affectedIndices) { + for (StubIndexKey key : allStubIndices) { stubIndex.getWriteLock(key).unlock(); } } @@ -344,24 +346,17 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi return stubTree; } + /*MUST be called from under the WriteLock*/ private Map readOldData(final int key) throws StorageException { - final Map result = new HashMap(); - final Lock lock = getReadLock(); - try { - lock.lock(); - final ValueContainer valueContainer = getData(key); - if (valueContainer.size() != 1) { - LOG.assertTrue(valueContainer.size() == 0); - return result; - } - result.put(key, valueContainer.getValueIterator().next()); - } - finally { - lock.unlock(); + final ValueContainer valueContainer = myStorage.read(key); + if (valueContainer.size() != 1) { + LOG.assertTrue(valueContainer.size() == 0); + return result; } + result.put(key, valueContainer.getValueIterator().next()); return result; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index a13e6cac860c..dbb2d0dd4630 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.*; +import java.util.concurrent.Callable; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -22,7 +23,7 @@ public class MapReduceIndex implements UpdatableIndex myIndexId; private final DataIndexer myIndexer; - private final IndexStorage myStorage; + protected final IndexStorage myStorage; private PersistentHashMap> myInputsIndex; private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock(); @@ -183,56 +184,51 @@ public class MapReduceIndex implements UpdatableIndex oldData = mapOld(oldContent); assert myInputsIndex != null; - - final Map data = mapNew(content); - Collection oldKeys; - try { - oldKeys = myInputsIndex.get(inputId); - } - catch (IOException e) { - throw new StorageException(e); - } - if (oldKeys == null) { - oldKeys = Collections.emptyList(); - } + final Map data = content != null ? myIndexer.map(content) : Collections.emptyMap(); + + updateWithMap(inputId, data, new Callable>() { + public Collection call() throws Exception { + final Collection oldKeys = myInputsIndex.get(inputId); + return oldKeys == null? Collections.emptyList() : oldKeys; + } + }); + } + + protected void updateWithMap(final int inputId, final Map newData, Callable> oldKeysGetter) throws StorageException { getWriteLock().lock(); try { - // remove outdated values - updateWithMap(inputId, data, oldKeys); try { - final Set newKeys = data.keySet(); - if (newKeys.size() > 0) { - myInputsIndex.put(inputId, newKeys); - } - else { - myInputsIndex.remove(inputId); + for (Key key : oldKeysGetter.call()) { + myStorage.removeAllValues(key, inputId); } } - catch (IOException e) { + catch (Exception e) { throw new StorageException(e); } + // add new values + for (Map.Entry entry : newData.entrySet()) { + myStorage.addValue(entry.getKey(), inputId, entry.getValue()); + } + if (myInputsIndex != null) { + try { + final Set newKeys = newData.keySet(); + if (newKeys.size() > 0) { + myInputsIndex.put(inputId, newKeys); + } + else { + myInputsIndex.remove(inputId); + } + } + catch (IOException e) { + throw new StorageException(e); + } + } } finally { getWriteLock().unlock(); } - } - - protected Map mapNew(final Input content) throws StorageException { - return content != null ? myIndexer.map(content) : Collections.emptyMap(); - } - - protected void updateWithMap(final int inputId, final Map newData, Collection oldKeys) throws StorageException { - for (Key key : oldKeys) { - myStorage.removeAllValues(key, inputId); - } - // add new values - for (Key key : newData.keySet()) { - final Value newValue = newData.get(key); - myStorage.addValue(key, inputId, newValue); - } scheduleFlush(); }