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
This commit is contained in:
Pavel V. Talanov
2017-07-14 20:40:00 +03:00
parent bc399444ab
commit f84cc7fb5b
2 changed files with 47 additions and 21 deletions
@@ -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.ScriptDependenciesResolver> {
) : kotlin.script.dependencies.DependenciesResolver,
DependencyResolverWrapper<kotlin.script.dependencies.ScriptDependenciesResolver>,
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
@@ -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<String, ModStampedRequest>()
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)