From f84cc7fb5bd0fe6c94d2f9d190dfcb365f994cd0 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Fri, 14 Jul 2017 20:40:00 +0300 Subject: [PATCH] Offload legacy dependency resolver work to a separate thread pool This is mainly to improve experience for kdsl users before gradle migrates to new API --- .../jetbrains/kotlin/script/legacyWrappers.kt | 11 ++-- .../core/script/ScriptDependenciesUpdater.kt | 57 +++++++++++++------ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/legacyWrappers.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/legacyWrappers.kt index b480acbf6a9..3fb73c3809b 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/legacyWrappers.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/legacyWrappers.kt @@ -24,11 +24,13 @@ import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptDependencies import kotlin.script.dependencies.ScriptReport +interface LegacyResolverWrapper + // NOTE: not implementing resolver wrapper since it was not implemented initially and this is deprecated API @Deprecated("Compatibility with deprecated API") internal class LegacyPackageDependencyResolverWrapper( val legacyResolver: ScriptDependenciesResolver -) : kotlin.script.dependencies.DependenciesResolver { +) : kotlin.script.dependencies.DependenciesResolver, LegacyResolverWrapper { override fun resolve( scriptContents: kotlin.script.dependencies.ScriptContents, environment: Environment @@ -68,8 +70,9 @@ internal class LegacyPackageDependencyResolverWrapper( internal class ApiChangeDependencyResolverWrapper( override val delegate: kotlin.script.dependencies.ScriptDependenciesResolver -) : kotlin.script.dependencies.DependenciesResolver, DependencyResolverWrapper { - +) : kotlin.script.dependencies.DependenciesResolver, + DependencyResolverWrapper, + LegacyResolverWrapper { override fun resolve( scriptContents: kotlin.script.dependencies.ScriptContents, environment: Environment @@ -93,7 +96,7 @@ internal class ApiChangeDependencyResolverWrapper( return DependenciesResolver.ResolveResult.Success(dependencies, reports) } - private fun kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.convertSeverity(): ScriptReport.Severity = when(this) { + private fun kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.convertSeverity(): ScriptReport.Severity = when (this) { kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.ERROR -> ScriptReport.Severity.ERROR kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.WARNING -> ScriptReport.Severity.WARNING kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.INFO -> ScriptReport.Severity.INFO diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt index fd07106c791..d2b467d2eca 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.script.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.Executors +import kotlin.script.dependencies.DependenciesResolver import kotlin.script.dependencies.ScriptDependencies import kotlin.script.dependencies.experimental.AsyncDependenciesResolver @@ -44,8 +45,12 @@ internal class ScriptDependenciesUpdater( private val scriptDefinitionProvider: KotlinScriptDefinitionProvider ) { private val requests = ConcurrentHashMap() - private val scriptDependencyUpdatesDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() private val contentLoader = ScriptContentLoader(project) + private val asyncUpdatesDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() + private val legacyUpdatesDispatcher = + Executors.newFixedThreadPool( + (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) + ).asCoroutineDispatcher() init { listenToVfsChanges() @@ -93,7 +98,7 @@ internal class ScriptDependenciesUpdater( val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return false return when (scriptDef.dependencyResolver) { - is AsyncDependenciesResolver -> { + is AsyncDependenciesResolver, is LegacyResolverWrapper -> { updateAsync(file, scriptDef) return false } @@ -134,26 +139,44 @@ internal class ScriptDependenciesUpdater( scriptDef: KotlinScriptDefinition ): TimeStampedJob { val currentTimeStamp = TimeStamps.next() - val dependenciesResolver = scriptDef.dependencyResolver as AsyncDependenciesResolver - val path = file.path - - val newJob = launch(scriptDependencyUpdatesDispatcher) { - val result = dependenciesResolver.resolveAsync( - contentLoader.getScriptContents(scriptDef, file), - contentLoader.getEnvironment(scriptDef) - ) - val lastTimeStamp = requests[path]?.job?.timeStamp - val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp - if (isLastSentRequest) { - ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) - if (cache(result.dependencies ?: ScriptDependencies.Empty, file)) { - onChange() - } + val dependenciesResolver = scriptDef.dependencyResolver + val newJob = if (dependenciesResolver is AsyncDependenciesResolver) { + launch(asyncUpdatesDispatcher) { + processResult( + file, currentTimeStamp, + dependenciesResolver.resolveAsync( + contentLoader.getScriptContents(scriptDef, file), + contentLoader.getEnvironment(scriptDef) + ) + ) + } + } + else { + assert(dependenciesResolver is LegacyResolverWrapper) + launch(legacyUpdatesDispatcher) { + processResult( + file, currentTimeStamp, + dependenciesResolver.resolve( + contentLoader.getScriptContents(scriptDef, file), + contentLoader.getEnvironment(scriptDef) + ) + ) } } return TimeStampedJob(newJob, currentTimeStamp) } + private fun processResult(file: VirtualFile, currentTimeStamp: TimeStamp, result: DependenciesResolver.ResolveResult) { + val lastTimeStamp = requests[file.path]?.job?.timeStamp + val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp + if (isLastSentRequest) { + ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) + if (cache(result.dependencies ?: ScriptDependencies.Empty, file)) { + onChange() + } + } + } + fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean { val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty return cache(newDeps, file)