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 844cd56ed79f..9809e3699dd3 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -351,6 +351,19 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } } + public void cleanupMemoryStorage() { + for (UpdatableIndex index : myIndices.values()) { + final IndexStorage indexStorage = ((MapReduceIndex)index).getStorage(); + index.getWriteLock().lock(); + try { + ((MemoryIndexStorage)indexStorage).clearMemoryMap(); + } + finally { + index.getWriteLock().unlock(); + } + } + } + public void clearAllIndices() { for (UpdatableIndex index : myIndices.values()) { 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 34635fc70b2d..bfab91fef771 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -217,6 +217,10 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi public void bufferingStateChanged(final boolean newState) { ((StubIndexImpl)StubIndexImpl.getInstance()).setDataBufferingEnabled(newState); } + + public void memoryStorageCleared() { + ((StubIndexImpl)StubIndexImpl.getInstance()).cleanupMemoryStorage(); + } }); } return new MyIndex(indexId, owner, storage, getIndexer()); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index aea6b47bb529..646901f738a1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -42,8 +42,10 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.psi.PsiDocumentManager; @@ -200,6 +202,20 @@ public class FileBasedIndex implements ApplicationComponent { } }); + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + public void before(List events) { + for (VFileEvent event : events) { + if (event.getRequestor() instanceof FileDocumentManager) { + cleanupMemoryStorage(); + break; + } + } + } + + public void after(List events) { + } + }); + ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { public void writeActionStarted(Object action) { myUpToDateIndices.clear(); @@ -257,7 +273,7 @@ public class FileBasedIndex implements ApplicationComponent { } } - private String calcConfigPath(final String path) { + private static String calcConfigPath(final String path) { try { final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); return _path.endsWith("/")? _path : _path + "/" ; @@ -1078,11 +1094,6 @@ public class FileBasedIndex implements ApplicationComponent { private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { final StorageGuard.Holder holder = myStorageLock.enter(enabled); - if (!enabled) { - synchronized (myLastIndexedDocStamps) { - myLastIndexedDocStamps.clear(); - } - } for (ID indexId : myIndices.keySet()) { final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); assert index != null; @@ -1092,6 +1103,25 @@ public class FileBasedIndex implements ApplicationComponent { return holder; } + private void cleanupMemoryStorage() { + synchronized (myLastIndexedDocStamps) { + myLastIndexedDocStamps.clear(); + } + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); + index.getWriteLock().lock(); + try { + memStorage.clearMemoryMap(); + } + finally { + index.getWriteLock().unlock(); + } + memStorage.fireMemoryStorageCleared(); + } + } + private void dropUnregisteredIndices() { final Set indicesToDrop = readRegistsredIndexNames(); for (ID key : myIndices.keySet()) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java index ec088797f505..1536a39d25d3 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java @@ -20,13 +20,14 @@ import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import java.io.Flushable; +import java.io.IOException; import java.util.Collection; /** * @author Eugene Zhuravlev * Date: Dec 10, 2007 */ -public interface IndexStorage extends Flushable{ +public interface IndexStorage extends Flushable { void addValue(Key key, int inputId, Value value) throws StorageException; @@ -44,4 +45,6 @@ public interface IndexStorage extends Flushable{ Collection getKeys() throws StorageException; void close() throws StorageException; + + void flush() throws IOException; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java index 699365c9f579..40c2247db498 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java @@ -137,7 +137,7 @@ public final class MapIndexStorage implements IndexStorage implements IndexStorage implements IndexStorage { private final Map> myMap = new HashMap>(); private final IndexStorage myBackendStorage; - private boolean myBufferingEnabled = false; private final List myListeners = ContainerUtil.createEmptyCOWList(); - private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock(); - private final JBLock r = myLock.readLock(); - private final JBLock w = myLock.writeLock(); - + private final AtomicBoolean myBufferingEnabled = new AtomicBoolean(false); + public interface BufferingStateListener { void bufferingStateChanged(boolean newState); + void memoryStorageCleared(); } public MemoryIndexStorage(IndexStorage backend) { @@ -59,21 +55,21 @@ public class MemoryIndexStorage implements IndexStorage } public void setBufferingEnabled(boolean enabled) { - w.lock(); - try { - final boolean wasEnabled = myBufferingEnabled; - myBufferingEnabled = enabled; - if (wasEnabled && !enabled) { - myMap.clear(); - } - if (wasEnabled != enabled) { - for (BufferingStateListener listener : myListeners) { - listener.bufferingStateChanged(enabled); - } + final boolean wasEnabled = myBufferingEnabled.getAndSet(enabled); + if (wasEnabled != enabled) { + for (BufferingStateListener listener : myListeners) { + listener.bufferingStateChanged(enabled); } } - finally { - w.unlock(); + } + + public void clearMemoryMap() { + myMap.clear(); + } + + public void fireMemoryStorageCleared() { + for (BufferingStateListener listener : myListeners) { + listener.memoryStorageCleared(); } } @@ -82,14 +78,8 @@ public class MemoryIndexStorage implements IndexStorage } public void clear() throws StorageException { - w.lock(); - try { - myMap.clear(); - myBackendStorage.clear(); - } - finally { - w.unlock(); - } + clearMemoryMap(); + myBackendStorage.clear(); } public void flush() throws IOException { @@ -103,75 +93,60 @@ public class MemoryIndexStorage implements IndexStorage } public boolean processKeys(final Processor processor) throws StorageException { - r.lock(); - try { - if (myBufferingEnabled) { - final Set stopList = new HashSet(); + final Set stopList = new HashSet(); - Processor decoratingProcessor = new Processor() { - public boolean process(final Key key) { - if (stopList.contains(key)) return true; + Processor decoratingProcessor = new Processor() { + public boolean process(final Key key) { + if (stopList.contains(key)) return true; - final UpdatableValueContainer container = myMap.get(key); - if (container != null && container.size() == 0) return true; - return processor.process(key); - } - }; - - for (Key key : myMap.keySet()) { - if (!decoratingProcessor.process(key)) return false; - stopList.add(key); - } - return myBackendStorage.processKeys(decoratingProcessor); + final UpdatableValueContainer container = myMap.get(key); + if (container != null && container.size() == 0) return true; + return processor.process(key); } - } - finally { - r.unlock(); - } + }; - return myBackendStorage.processKeys(processor); + for (Key key : myMap.keySet()) { + if (!decoratingProcessor.process(key)) return false; + stopList.add(key); + } + return myBackendStorage.processKeys(decoratingProcessor); } public void addValue(final Key key, final int inputId, final Value value) throws StorageException { - w.lock(); - try { - if (myBufferingEnabled) { - getMemValueContainer(key).addValue(inputId, value); - return; - } + if (myBufferingEnabled.get()) { + getMemValueContainer(key).addValue(inputId, value); + return; } - finally { - w.unlock(); + final UpdatableValueContainer valueContainer = myMap.get(key); + if (valueContainer != null) { + valueContainer.addValue(inputId, value); } myBackendStorage.addValue(key, inputId, value); } public void removeValue(final Key key, final int inputId, final Value value) throws StorageException { - w.lock(); - try { - if (myBufferingEnabled) { - getMemValueContainer(key).removeValue(inputId, value); - return; - } + if (myBufferingEnabled.get()) { + getMemValueContainer(key).removeValue(inputId, value); + return; } - finally { - w.unlock(); + final UpdatableValueContainer valueContainer = myMap.get(key); + if (valueContainer != null) { + valueContainer.removeValue(inputId, value); } myBackendStorage.removeValue(key, inputId, value); } public void removeAllValues(Key key, int inputId) throws StorageException { - w.lock(); - try { - if (myBufferingEnabled) { - getMemValueContainer(key).removeAllValues(inputId); - return; - } + if (myBufferingEnabled.get()) { + getMemValueContainer(key).removeAllValues(inputId); + return; } - finally { - w.unlock(); + final UpdatableValueContainer valueContainer = myMap.get(key); + if (valueContainer != null) { + valueContainer.removeAllValues(inputId); } + myBackendStorage.removeAllValues(key, inputId); } @@ -199,18 +174,9 @@ public class MemoryIndexStorage implements IndexStorage @NotNull public ValueContainer read(final Key key) throws StorageException { - r.lock(); - try { - if (myBufferingEnabled) { - final ValueContainer valueContainer = myMap.get(key); - if (valueContainer != null) { - return valueContainer; - } - return myBackendStorage.read(key); - } - } - finally { - r.unlock(); + final ValueContainer valueContainer = myMap.get(key); + if (valueContainer != null) { + return valueContainer; } return myBackendStorage.read(key);