diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java index 7b919c9bfd01..a27d25160856 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java @@ -330,6 +330,7 @@ public final class PushedFilePropertiesUpdaterImpl extends PushedFilePropertiesU invokeConcurrentlyIfPossible(tasks); } + // TODO: this method may return earlier than all spawned threads have completed. public static void invokeConcurrentlyIfPossible(@NotNull List tasks) { if (tasks.isEmpty()) return; if (tasks.size() == 1 || ApplicationManager.getApplication().isWriteAccessAllowed()) { 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 3a16492fa46f..8471257ab8e0 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -47,6 +47,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.*; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; public final class UnindexedFilesUpdater extends DumbModeTask { @@ -332,6 +333,11 @@ public final class UnindexedFilesUpdater extends DumbModeTask { ConcurrentTasksProgressManager concurrentTasksProgressManager = new ConcurrentTasksProgressManager(indicator, providers.size()); + // Workaround for concurrent modification of the [projectIndexingHistory]. + // PushedFilePropertiesUpdaterImpl.invokeConcurrentlyIfPossible may finish earlier than all its spawned tasks have completed. + // And some scanning statistics may be tried to be added to the [projectIndexingHistory], + // leading to ConcurrentModificationException in the statistics' processor. + AtomicBoolean allTasksFinished = new AtomicBoolean(); List tasks = ContainerUtil.map(providers, provider -> { SubTaskProgressIndicator subTaskIndicator = concurrentTasksProgressManager.createSubTaskIndicator(1); List files = new ArrayList<>(); @@ -374,14 +380,20 @@ public final class UnindexedFilesUpdater extends DumbModeTask { finally { scanningStatistics.setNumberOfSkippedFiles(thisProviderDeduplicateFilter.getNumberOfSkippedFiles()); synchronized (projectIndexingHistory) { - projectIndexingHistory.addScanningStatistics(scanningStatistics); + if (!allTasksFinished.get()) { + projectIndexingHistory.addScanningStatistics(scanningStatistics); + } } subTaskIndicator.finished(); } }; }); LOG.info("Scanning: use " + getNumberOfScanningThreads() + " scanning threads"); - PushedFilePropertiesUpdaterImpl.invokeConcurrentlyIfPossible(tasks); + try { + PushedFilePropertiesUpdaterImpl.invokeConcurrentlyIfPossible(tasks); + } finally { + allTasksFinished.set(true); + } return providerToFiles; }