From 08f41f30bb9d8916bc02112e46280c3a3ec4491d Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 23 Sep 2009 15:59:02 +0400 Subject: [PATCH] background index update for modified files --- .../indexing/BackgroundCacheUpdaterRunner.java | 201 +++++++++++++++++++++ .../com/intellij/util/indexing/FileBasedIndex.java | 19 +- .../util/indexing/UnindexedFilesUpdater.java | 146 +-------------- 3 files changed, 220 insertions(+), 146 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/BackgroundCacheUpdaterRunner.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/BackgroundCacheUpdaterRunner.java b/platform/lang-impl/src/com/intellij/util/indexing/BackgroundCacheUpdaterRunner.java new file mode 100644 index 0000000000..c0fac559b9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/BackgroundCacheUpdaterRunner.java @@ -0,0 +1,201 @@ +package com.intellij.util.indexing; + +import com.intellij.ide.startup.CacheUpdater; +import com.intellij.ide.startup.FileContent; +import com.intellij.ide.startup.FileContentQueue; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; +import com.intellij.openapi.project.DumbServiceImpl; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import com.intellij.util.containers.HashMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: Sep 22, 2009 + */ +public class BackgroundCacheUpdaterRunner { + private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.BackgroundCacheUpdaterRunner"); + private static final Key DONT_INDEX_AGAIN_KEY = Key.create("DONT_INDEX_AGAIN_KEY"); + private final Map> myProjectToFileMap; // todo: --> Map + + public BackgroundCacheUpdaterRunner(Project project, Collection files) { + myProjectToFileMap = Collections.singletonMap(project, files); + } + + public BackgroundCacheUpdaterRunner(Collection files) { + myProjectToFileMap = new HashMap>(); + for (VirtualFile file : files) { + final Project project = ProjectUtil.guessProjectForFile(file); + Collection list = myProjectToFileMap.get(project); + if (list == null) { + myProjectToFileMap.put(project, list = new ArrayList()); + } + list.add(file); + } + } + + public void processFiles(final CacheUpdater updater) { + for (Map.Entry> entry : myProjectToFileMap.entrySet()) { + final Project project = entry.getKey(); + final Collection files = entry.getValue(); + + final Consumer action = new Consumer() { + public void consume(final ProgressIndicator indicator) { + final MyFileContentQueue queue = new MyFileContentQueue(); + + try { + final double count = files.size(); + queue.queue(files, indicator); + + final Consumer uiUpdater = new Consumer() { + final Set processed = new THashSet(); + + public void consume(VirtualFile virtualFile) { + indicator.checkCanceled(); + indicator.setFraction(processed.size() / count); + processed.add(virtualFile); + indicator.setText2(virtualFile.getPresentableUrl()); + } + }; + + while (!project.isDisposed()) { + indicator.checkCanceled(); + if (runWhileUserInactive(project, queue, uiUpdater, updater)) { + break; + } + } + if (project.isDisposed()) { + indicator.cancel(); + } + } + finally { + queue.clear(); + updater.updatingDone(); + } + } + }; + if (project != null) { + DumbServiceImpl.getInstance(project).queueIndexUpdate(action); + } + else { + final ProgressIndicator currentIndicator = ProgressManager.getInstance().getProgressIndicator(); + action.consume(currentIndicator != null? currentIndicator : new EmptyProgressIndicator()); + } + } + } + + private boolean runWhileUserInactive(final Project project, final MyFileContentQueue queue, final Consumer updateUi, final CacheUpdater updater) { + final ProgressIndicatorBase innerIndicator = new ProgressIndicatorBase(); + final ApplicationAdapter canceller = new ApplicationAdapter() { + @Override + public void beforeWriteActionStart(Object action) { + innerIndicator.cancel(); + } + }; + + final Ref finished = Ref.create(Boolean.FALSE); + ProgressManager.getInstance().runProcess(new Runnable() { + public void run() { + ApplicationManager.getApplication().addApplicationListener(canceller); + try { + while (true) { + if (project != null && project.isDisposed()) return; + + final com.intellij.ide.startup.FileContent fileContent = queue.take(); + if (fileContent == null) { + finished.set(Boolean.TRUE); + return; + } + + final VirtualFile file = fileContent.getVirtualFile(); + if (file == null) { + finished.set(Boolean.TRUE); + return; + } + + try { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + innerIndicator.checkCanceled(); + + if (!file.isValid()) { + return; + } + + if (project != null && project.isDisposed()) { + return; + } + + updateUi.consume(file); + + if (project != null) { + fileContent.putUserData(FileBasedIndex.PROJECT, project); + } + updater.processFile(fileContent); + + innerIndicator.checkCanceled(); + } + }); + } + catch (ProcessCanceledException e) { + queue.pushback(fileContent); + return; + } + catch (Throwable e) { + LOG.error("Error while indexing " + file.getPresentableUrl() + "\n" + "To reindex this file IDEA has to be restarted", e); + file.putUserData(DONT_INDEX_AGAIN_KEY, Boolean.TRUE); + } + } + } + finally { + ApplicationManager.getApplication().removeApplicationListener(canceller); + } + } + }, innerIndicator); + + return finished.get().booleanValue(); + } + + private static class MyFileContentQueue extends FileContentQueue { + @Nullable private FileContent myBuffer; + + @Override + protected void addLast(VirtualFile file) throws InterruptedException { + IndexingStamp.flushCache(); + super.addLast(file); + } + + @Override + public FileContent take() { + final FileContent buffer = myBuffer; + if (buffer != null) { + myBuffer = null; + return buffer; + } + + return super.take(); + } + + public void pushback(@NotNull FileContent content) { + myBuffer = content; + } + + } + +} 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 c8d1f240a7..18373a9092 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -3,7 +3,7 @@ package com.intellij.util.indexing; import com.intellij.AppTopics; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobScheduler; -import com.intellij.ide.startup.CacheUpdater; +import com.intellij.ide.startup.BackgroundableCacheUpdater; import com.intellij.ide.startup.impl.FileSystemSynchronizerImpl; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.*; @@ -1197,7 +1197,7 @@ public class FileBasedIndex implements ApplicationComponent { return !myNotRequiringContentIndices.contains(indexId); } - private final class ChangedFilesUpdater extends VirtualFileAdapter implements CacheUpdater{ + private final class ChangedFilesUpdater extends VirtualFileAdapter implements BackgroundableCacheUpdater { private final Set myFilesToUpdate = new LinkedHashSet(); private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock(); private final JBLock r = myLock.readLock(); @@ -1388,6 +1388,21 @@ public class FileBasedIndex implements ApplicationComponent { } } + public boolean initiallyBackgrounded() { + if (ApplicationManager.getApplication().isCommandLine() || ApplicationManager.getApplication().isUnitTestMode()) { + return false; + } + return Registry.get(DumbServiceImpl.FILE_INDEX_BACKGROUND).asBoolean(); + } + + public boolean canBeSentToBackground(Collection remaining) { + return true; + } + + public void backgrounded(Collection remaining) { + new BackgroundCacheUpdaterRunner(remaining).processFiles(this); + } + public VirtualFile[] queryNeededFiles() { r.lock(); try { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index bdee0d1f60..d8933c9f2b 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -2,32 +2,24 @@ package com.intellij.util.indexing; import com.intellij.ide.startup.BackgroundableCacheUpdater; import com.intellij.ide.startup.FileContent; -import com.intellij.ide.startup.FileContentQueue; -import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.DumbServiceImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.util.Consumer; import com.intellij.util.containers.HashSet; import com.intellij.util.ui.UIUtil; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -94,121 +86,13 @@ public class UnindexedFilesUpdater implements BackgroundableCacheUpdater { } public void backgrounded(final Collection remaining) { - DumbServiceImpl.getInstance(myProject).queueIndexUpdate(new Consumer() { - public void consume(final ProgressIndicator indicator) { - final MyFileContentQueue queue = new MyFileContentQueue(); - - try { - final double count = remaining.size(); - queue.queue(remaining, indicator); - - final Consumer uiUpdater = new Consumer() { - final Set processed = new THashSet(); - - public void consume(VirtualFile virtualFile) { - indicator.checkCanceled(); - indicator.setFraction(processed.size() / count); - processed.add(virtualFile); - indicator.setText2(virtualFile.getPresentableUrl()); - } - }; - - while (!myProject.isDisposed()) { - indicator.checkCanceled(); - if (runUntilNextWriteAction(queue, uiUpdater)) { - break; - } - } - if (myProject.isDisposed()) { - indicator.cancel(); - } - } - finally { - queue.clear(); - updatingDone(); - } - } - }); - } - - private boolean runUntilNextWriteAction(final MyFileContentQueue queue, final Consumer updateUi) { - final ProgressIndicatorBase innerIndicator = new ProgressIndicatorBase(); - final ApplicationAdapter canceller = new ApplicationAdapter() { - @Override - public void beforeWriteActionStart(Object action) { - innerIndicator.cancel(); - } - }; - - final Ref finished = Ref.create(Boolean.FALSE); - ProgressManager.getInstance().runProcess(new Runnable() { - public void run() { - ApplicationManager.getApplication().addApplicationListener(canceller); - try { - while (true) { - if (myProject.isDisposed()) return; - - final FileContent fileContent = queue.take(); - if (fileContent == null) { - finished.set(Boolean.TRUE); - return; - } - - final VirtualFile file = fileContent.getVirtualFile(); - if (file == null) { - finished.set(Boolean.TRUE); - return; - } - - try { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - innerIndicator.checkCanceled(); - - if (!file.isValid()) { - return; - } - - if (myProject.isDisposed()) { - return; - } - - updateUi.consume(file); - - doProcessFile(fileContent); - - innerIndicator.checkCanceled(); - } - }); - } - catch (ProcessCanceledException e) { - queue.pushback(fileContent); - return; - } - catch (Throwable e) { - LOG.error("Error while indexing " + file.getPresentableUrl() + "\n" + "To reindex this file IDEA has to be restarted", - e); - file.putUserData(DONT_INDEX_AGAIN_KEY, Boolean.TRUE); - } - } - } - finally { - ApplicationManager.getApplication().removeApplicationListener(canceller); - } - } - }, innerIndicator); - - return finished.get().booleanValue(); + new BackgroundCacheUpdaterRunner(myProject, remaining).processFiles(this); } public void processFile(final FileContent fileContent) { - doProcessFile(fileContent); - IndexingStamp.flushCache(); - } - - private void doProcessFile(FileContent fileContent) { fileContent.putUserData(FileBasedIndex.PROJECT, myProject); myIndex.indexFileContent(fileContent); + IndexingStamp.flushCache(); } private void iterateIndexableFiles(final ContentIterator processor) { @@ -279,30 +163,4 @@ public class UnindexedFilesUpdater implements BackgroundableCacheUpdater { public void canceled() { myIndex.flushCaches(); } - - private static class MyFileContentQueue extends FileContentQueue { - @Nullable private FileContent myBuffer; - - @Override - protected void addLast(VirtualFile file) throws InterruptedException { - IndexingStamp.flushCache(); - super.addLast(file); - } - - @Override - public FileContent take() { - final FileContent buffer = myBuffer; - if (buffer != null) { - myBuffer = null; - return buffer; - } - - return super.take(); - } - - public void pushback(@NotNull FileContent content) { - myBuffer = content; - } - - } } -- 2.11.4.GIT