diff --git a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy index b884a753d33a..5179fec5f5bf 100644 --- a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy @@ -60,7 +60,9 @@ import com.intellij.util.indexing.* import com.intellij.util.indexing.impl.MapIndexStorage import com.intellij.util.indexing.impl.MapReduceIndex import com.intellij.util.indexing.impl.UpdatableValueContainer -import com.intellij.util.io.* +import com.intellij.util.io.CaseInsensitiveEnumeratorStringDescriptor +import com.intellij.util.io.EnumeratorStringDescriptor +import com.intellij.util.io.PersistentHashMap import com.intellij.util.ref.GCUtil import com.intellij.util.ref.GCWatcher import com.siyeh.ig.JavaOverridingMethodUtil @@ -800,10 +802,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { void testIndexedFilesListener() throws Throwable { def listener = new RecordingVfsListener() - ApplicationManager.getApplication().getMessageBus().connect(myFixture.getTestRootDisposable()).subscribe( - VirtualFileManager.VFS_CHANGES, - listener - ) + VirtualFileManager.instance.addAsyncFileListener(listener, myFixture.testRootDisposable) def fileName = "test.txt" final VirtualFile testFile = myFixture.addFileToProject(fileName, "test").getVirtualFile() @@ -912,7 +911,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { } @CompileStatic - void "test Vfs Events Processing Performance"() { + void "test Vfs Event Processing Performance"() { def filename = 'A.java' myFixture.addFileToProject('foo/bar/' + filename, 'class A {}') @@ -934,9 +933,9 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, null, true, null)) } - IndexedFilesListener indexedFilesListener = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector - indexedFilesListener.before(eventList) - indexedFilesListener.after(eventList) + def applier = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector.prepareChange(eventList) + applier.beforeVfsChange() + applier.afterVfsChange() files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.moduleScope(module)) assert files?.length == 1 diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index e0621e0f88d2..8d99bc2165b8 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -36,10 +36,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.vfs.VirtualFileWithId; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; @@ -262,7 +259,7 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab myChangedFilesCollector = new ChangedFilesCollector(); myConnection = connection; - connection.subscribe(VirtualFileManager.VFS_CHANGES, myChangedFilesCollector); + VirtualFileManager.getInstance().addAsyncFileListener(myChangedFilesCollector, this); initComponent(); } @@ -311,7 +308,7 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab // but it is more costly than current code, see IDEA-192192 //myChangedFilesCollector.invalidateIndicesRecursively(file, false); //myChangedFilesCollector.buildIndicesForFileRecursively(file, false); - myChangedFilesCollector.invalidateIndicesRecursively(file, true); + myChangedFilesCollector.invalidateIndicesRecursively(file, true, myChangedFilesCollector.getEventMerger()); if (myInitialized) myChangedFilesCollector.ensureUpToDateAsync(); } @@ -1939,14 +1936,26 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab } @Override - public void before(@NotNull List events) { - for (VFileEvent event : events) { - if (memoryStorageCleaningNeeded(event)) { - cleanupMemoryStorage(false); - break; + @NotNull + public AsyncFileListener.ChangeApplier prepareChange(@NotNull List events) { + boolean shouldCleanup = ContainerUtil.exists(events, this::memoryStorageCleaningNeeded); + ChangeApplier superApplier = super.prepareChange(events); + + return new AsyncFileListener.ChangeApplier() { + @Override + public void beforeVfsChange() { + if (shouldCleanup) { + cleanupMemoryStorage(false); + } + superApplier.beforeVfsChange(); } - } - super.before(events); + + @Override + public void afterVfsChange() { + superApplier.afterVfsChange(); + if (myInitialized) ensureUpToDateAsync(); + } + }; } private boolean memoryStorageCleaningNeeded(VFileEvent event) { @@ -1956,13 +1965,6 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab requestor == LocalHistory.VFS_EVENT_REQUESTOR; } - @Override - public void after(@NotNull List events) { - super.after(events); - - if (myInitialized) ensureUpToDateAsync(); - } - boolean isScheduledForUpdate(VirtualFile file) { return myFilesToUpdate.containsKey(Math.abs(getIdMaskingNonIdBasedFile(file))); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexedFilesListener.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexedFilesListener.java index 544c73f717fd..c27d469d7858 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexedFilesListener.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexedFilesListener.java @@ -16,12 +16,9 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.roots.ContentIterator; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileVisitor; -import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.events.*; @@ -31,7 +28,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.List; -public abstract class IndexedFilesListener implements BulkFileListener { +public abstract class IndexedFilesListener implements AsyncFileListener { private final ManagingFS myManagingFS = ManagingFS.getInstance(); private final VfsEventsMerger myEventMerger = new VfsEventsMerger(); @Nullable private final VirtualFile myConfig; @@ -60,21 +57,22 @@ public abstract class IndexedFilesListener implements BulkFileListener { } } - private boolean invalidateIndicesForFile(@NotNull VirtualFile file, boolean contentChange) { + private boolean invalidateIndicesForFile(@NotNull VirtualFile file, boolean contentChange, VfsEventsMerger eventMerger) { if (isUnderConfigOrSystem(file)) { return false; } - myEventMerger.recordBeforeFileEvent(file, contentChange); + ProgressManager.checkCanceled(); + eventMerger.recordBeforeFileEvent(file, contentChange); return !file.isDirectory() || FileBasedIndexImpl.isMock(file) || myManagingFS.wereChildrenAccessed(file); } protected abstract void iterateIndexableFiles(@NotNull VirtualFile file, @NotNull ContentIterator iterator); - void invalidateIndicesRecursively(@NotNull final VirtualFile file, final boolean contentChange) { + void invalidateIndicesRecursively(@NotNull VirtualFile file, boolean contentChange, VfsEventsMerger eventMerger) { VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() { @Override public boolean visitFile(@NotNull VirtualFile file) { - return invalidateIndicesForFile(file, contentChange); + return invalidateIndicesForFile(file, contentChange, eventMerger); } @Override @@ -85,13 +83,15 @@ public abstract class IndexedFilesListener implements BulkFileListener { } @Override - public void before(@NotNull List events) { + @NotNull + public ChangeApplier prepareChange(@NotNull List events) { + VfsEventsMerger tempMerger = new VfsEventsMerger(); for (VFileEvent event : events) { if (event instanceof VFileContentChangeEvent) { - invalidateIndicesRecursively(((VFileContentChangeEvent)event).getFile(), true); + invalidateIndicesRecursively(((VFileContentChangeEvent)event).getFile(), true, tempMerger); } else if (event instanceof VFileDeleteEvent) { - invalidateIndicesRecursively(((VFileDeleteEvent)event).getFile(), false); + invalidateIndicesRecursively(((VFileDeleteEvent)event).getFile(), false, tempMerger); } else if (event instanceof VFilePropertyChangeEvent) { final VFilePropertyChangeEvent pce = (VFilePropertyChangeEvent)event; @@ -100,16 +100,26 @@ public abstract class IndexedFilesListener implements BulkFileListener { // indexes may depend on file name // name change may lead to filetype change so the file might become not indexable // in general case have to 'unindex' the file and index it again if needed after the name has been changed - invalidateIndicesRecursively(pce.getFile(), false); + invalidateIndicesRecursively(pce.getFile(), false, tempMerger); } else if (propertyName.equals(VirtualFile.PROP_ENCODING)) { - invalidateIndicesRecursively(pce.getFile(), true); + invalidateIndicesRecursively(pce.getFile(), true, tempMerger); } } } + return new ChangeApplier() { + @Override + public void beforeVfsChange() { + myEventMerger.applyMergedEvents(tempMerger); + } + + @Override + public void afterVfsChange() { + processAfterEvents(events); + } + }; } - @Override - public void after(@NotNull List events) { + private void processAfterEvents(@NotNull List events) { for (VFileEvent event : events) { if (event instanceof VFileContentChangeEvent) { buildIndicesForFileRecursively(((VFileContentChangeEvent)event).getFile(), true); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java b/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java index 67b56c53b68e..befa938c8b98 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java @@ -66,6 +66,12 @@ public class VfsEventsMerger { } } + public void applyMergedEvents(VfsEventsMerger merger) { + for(ChangeInfo info:merger.myChangeInfos.values()) { + updateChange(info.getFileId(), info.file, info.eventMask); + } + } + @FunctionalInterface public interface VfsEventProcessor { boolean process(@NotNull ChangeInfo changeInfo);