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.ScriptDependencies
import kotlin.script.dependencies.ScriptReport import kotlin.script.dependencies.ScriptReport
interface LegacyResolverWrapper
// NOTE: not implementing resolver wrapper since it was not implemented initially and this is deprecated API // NOTE: not implementing resolver wrapper since it was not implemented initially and this is deprecated API
@Deprecated("Compatibility with deprecated API") @Deprecated("Compatibility with deprecated API")
internal class LegacyPackageDependencyResolverWrapper( internal class LegacyPackageDependencyResolverWrapper(
val legacyResolver: ScriptDependenciesResolver val legacyResolver: ScriptDependenciesResolver
) : kotlin.script.dependencies.DependenciesResolver { ) : kotlin.script.dependencies.DependenciesResolver, LegacyResolverWrapper {
override fun resolve( override fun resolve(
scriptContents: kotlin.script.dependencies.ScriptContents, scriptContents: kotlin.script.dependencies.ScriptContents,
environment: Environment environment: Environment
@@ -68,8 +70,9 @@ internal class LegacyPackageDependencyResolverWrapper(
internal class ApiChangeDependencyResolverWrapper( internal class ApiChangeDependencyResolverWrapper(
override val delegate: kotlin.script.dependencies.ScriptDependenciesResolver 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( override fun resolve(
scriptContents: kotlin.script.dependencies.ScriptContents, scriptContents: kotlin.script.dependencies.ScriptContents,
environment: Environment environment: Environment
@@ -93,7 +96,7 @@ internal class ApiChangeDependencyResolverWrapper(
return DependenciesResolver.ResolveResult.Success(dependencies, reports) 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.ERROR -> ScriptReport.Severity.ERROR
kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.WARNING -> ScriptReport.Severity.WARNING kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.WARNING -> ScriptReport.Severity.WARNING
kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity.INFO -> ScriptReport.Severity.INFO 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 org.jetbrains.kotlin.script.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.script.dependencies.DependenciesResolver
import kotlin.script.dependencies.ScriptDependencies import kotlin.script.dependencies.ScriptDependencies
import kotlin.script.dependencies.experimental.AsyncDependenciesResolver import kotlin.script.dependencies.experimental.AsyncDependenciesResolver
@@ -44,8 +45,12 @@ internal class ScriptDependenciesUpdater(
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider private val scriptDefinitionProvider: KotlinScriptDefinitionProvider
) { ) {
private val requests = ConcurrentHashMap<String, ModStampedRequest>() private val requests = ConcurrentHashMap<String, ModStampedRequest>()
private val scriptDependencyUpdatesDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
private val contentLoader = ScriptContentLoader(project) 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 { init {
listenToVfsChanges() listenToVfsChanges()
@@ -93,7 +98,7 @@ internal class ScriptDependenciesUpdater(
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return false val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return false
return when (scriptDef.dependencyResolver) { return when (scriptDef.dependencyResolver) {
is AsyncDependenciesResolver -> { is AsyncDependenciesResolver, is LegacyResolverWrapper -> {
updateAsync(file, scriptDef) updateAsync(file, scriptDef)
return false return false
} }
@@ -134,26 +139,44 @@ internal class ScriptDependenciesUpdater(
scriptDef: KotlinScriptDefinition scriptDef: KotlinScriptDefinition
): TimeStampedJob { ): TimeStampedJob {
val currentTimeStamp = TimeStamps.next() val currentTimeStamp = TimeStamps.next()
val dependenciesResolver = scriptDef.dependencyResolver as AsyncDependenciesResolver val dependenciesResolver = scriptDef.dependencyResolver
val path = file.path val newJob = if (dependenciesResolver is AsyncDependenciesResolver) {
launch(asyncUpdatesDispatcher) {
val newJob = launch(scriptDependencyUpdatesDispatcher) { processResult(
val result = dependenciesResolver.resolveAsync( file, currentTimeStamp,
contentLoader.getScriptContents(scriptDef, file), dependenciesResolver.resolveAsync(
contentLoader.getEnvironment(scriptDef) 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)) { else {
onChange() assert(dependenciesResolver is LegacyResolverWrapper)
} launch(legacyUpdatesDispatcher) {
processResult(
file, currentTimeStamp,
dependenciesResolver.resolve(
contentLoader.getScriptContents(scriptDef, file),
contentLoader.getEnvironment(scriptDef)
)
)
} }
} }
return TimeStampedJob(newJob, currentTimeStamp) 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 { fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean {
val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty
return cache(newDeps, file) return cache(newDeps, file)