diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt index 855e728ed480..6b3d26fa1d83 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt @@ -28,12 +28,12 @@ import org.jetbrains.idea.maven.plugins.api.MavenModelPropertiesPatcher import org.jetbrains.idea.maven.server.MavenGoalExecutionResult import org.jetbrains.idea.maven.utils.MavenArtifactUtil.hasArtifactFile import org.jetbrains.idea.maven.utils.MavenLog -import org.jetbrains.idea.maven.utils.MavenPathWrapper import org.jetbrains.idea.maven.utils.MavenUtil import java.io.* import java.nio.file.Path import java.util.* import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList import java.util.function.Predicate import kotlin.io.path.isDirectory @@ -50,6 +50,7 @@ class MavenProject(val file: VirtualFile) { private val cache = ConcurrentHashMap, Any>() private val stateCache = ConcurrentHashMap, Any>() + private val problemsCache = CopyOnWriteArrayList() enum class ProcMode { BOTH, ONLY, NONE @@ -434,17 +435,13 @@ class MavenProject(val file: VirtualFile) { val problems: List get() { - return collectProblems(null) + return problemsCache } - @Internal - fun collectProblems(fileExistsPredicate: Predicate?): List { - var problemsCache = getStateCachedValue(PROBLEMS_CACHE_KEY) - if (problemsCache == null) { - problemsCache = doCollectProblems(file, fileExistsPredicate) - putStateCachedValue(PROBLEMS_CACHE_KEY, problemsCache) - } - return problemsCache + internal fun collectProblems(fileExistsPredicate: Predicate?) { + val collectedProblems = doCollectProblems(file, fileExistsPredicate) + problemsCache.clear() + problemsCache.addAll(collectedProblems) } private fun doCollectProblems(file: VirtualFile, fileExistsPredicate: Predicate?): List { @@ -803,7 +800,6 @@ class MavenProject(val file: VirtualFile) { companion object { private val DEPENDENCIES_CACHE_KEY: Key = Key.create("MavenProject.DEPENDENCIES_CACHE_KEY") private val FILTERS_CACHE_KEY: Key> = Key.create("MavenProject.FILTERS_CACHE_KEY") - private val PROBLEMS_CACHE_KEY: Key> = Key.create("MavenProject.PROBLEMS_CACHE_KEY") private val UNRESOLVED_DEPENDENCIES_CACHE_KEY: Key> = Key.create("MavenProject.UNRESOLVED_DEPENDENCIES_CACHE_KEY") private val UNRESOLVED_PLUGINS_CACHE_KEY: Key> = Key.create("MavenProject.UNRESOLVED_PLUGINS_CACHE_KEY") private val UNRESOLVED_EXTENSIONS_CACHE_KEY: Key> = Key.create("MavenProject.UNRESOLVED_EXTENSIONS_CACHE_KEY") diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerEx.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerEx.kt index 86e7739f854b..c6304c895ba7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerEx.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerEx.kt @@ -58,8 +58,6 @@ import org.jetbrains.idea.maven.telemetry.tracer import org.jetbrains.idea.maven.utils.MavenActivityKey import org.jetbrains.idea.maven.utils.MavenLog import org.jetbrains.idea.maven.utils.MavenUtil -import java.io.File -import java.nio.file.Files @ApiStatus.Experimental interface MavenAsyncProjectsManager { @@ -113,10 +111,6 @@ interface MavenAsyncProjectsManager { syncProject: Boolean, ): List - fun projectFileExists(file: File): Boolean { - return Files.exists(file.toPath()) - } - suspend fun onProjectStartup() } @@ -468,6 +462,10 @@ open class MavenProjectsManagerEx(project: Project, private val cs: CoroutineSco importModules(syncActivity, resolutionResult, modelsProvider, mavenEmbedderWrappers) } + tracer.spanBuilder("collectMavenProblems").useWithScope { + projectsTree.collectProblems() + } + tracer.spanBuilder("notifyMavenProblems").useWithScope { MavenResolveResultProblemProcessor.notifyMavenProblems(myProject) } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt index e29018736f7d..1fd44e7daf3b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt @@ -25,6 +25,7 @@ import com.intellij.util.containers.DisposableWrapperList import com.intellij.util.containers.FileCollectionFactory import it.unimi.dsi.fastutil.Hash import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet +import kotlinx.coroutines.* import org.jdom.output.Format import org.jdom.output.XMLOutputter import org.jetbrains.annotations.ApiStatus @@ -36,12 +37,15 @@ import org.jetbrains.idea.maven.server.NativeMavenProjectHolder import org.jetbrains.idea.maven.telemetry.tracer import org.jetbrains.idea.maven.utils.* import java.io.* +import java.lang.Runnable import java.nio.file.Files import java.nio.file.Path import java.util.* +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.function.Consumer +import java.util.function.Predicate import java.util.regex.Pattern import java.util.zip.CRC32 @@ -1104,6 +1108,23 @@ class MavenProjectsTree(val project: Project) { } + internal suspend fun collectProblems() { + val existingFiles = ConcurrentHashMap() + val fileExistsPredicate = Predicate { f: File -> existingFiles.computeIfAbsent(f) { file: File -> Files.exists(file.toPath()) } } + + coroutineScope { + withContext(Dispatchers.IO) { + projects.forEach { project -> + launch(CoroutineName("collecting problems in ${project.name}")) { + tracer.spanBuilder("collectProblems").useWithScope { + project.collectProblems(fileExistsPredicate) // fill problem cache + } + } + } + } + } + } + @ApiStatus.Internal fun read(path: Path) { if (!Files.exists(path)) return diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTreeUpdateContext.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTreeUpdateContext.java index 728a1d47b2ce..4c779052564b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTreeUpdateContext.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTreeUpdateContext.java @@ -4,12 +4,9 @@ package org.jetbrains.idea.maven.project; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.utils.ParallelRunner; -import java.io.File; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; @ApiStatus.Internal class MavenProjectsTreeUpdateContext { @@ -45,18 +42,6 @@ class MavenProjectsTreeUpdateContext { } private @NotNull List> mapToListWithPairs() { - var existingFiles = new ConcurrentHashMap(); - Predicate fileExistsPredicate = f -> { - return existingFiles.computeIfAbsent(f, file -> { - return MavenProjectsManagerEx.getInstance(myTree.getProject()).projectFileExists(file); - }); - }; - - ParallelRunner.getInstance(myTree.getProject()).runInParallelBlocking(updatedProjectsWithChanges.keySet(), mavenProject -> { - mavenProject.collectProblems(fileExistsPredicate); // need for fill problem cache - return null; - }); - ArrayList> result = new ArrayList<>(updatedProjectsWithChanges.size()); for (Map.Entry entry : updatedProjectsWithChanges.entrySet()) { result.add(Pair.create(entry.getKey(), entry.getValue())); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectsTreeReadingTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectsTreeReadingTest.kt index 8186808497b8..07487044b2f1 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectsTreeReadingTest.kt +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectsTreeReadingTest.kt @@ -608,6 +608,7 @@ class MavenProjectsTreeReadingTest : MavenProjectsTreeTestCase() { val mavenProject = tree.findProject(projectPom)!! resolve(project, mavenProject, mavenGeneralSettings) assertEquals(log().add("resolved", "project"), listener.log) + updateAllProjects() assertFalse(mavenProject.problems.isEmpty()) }