From 45600830d3fc346b5e410d45cae7ce8da7e4da83 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Tue, 7 Jul 2020 19:15:32 +0000 Subject: [PATCH] Fixed locking granularity in ScriptDefinitionsManager #KT-34552 Fixed #KT-39547 Fixed --- .../core/script/ScriptDefinitionsManager.kt | 69 ++++++++++--------- ...ScriptTemplatesFromDependenciesProvider.kt | 1 + 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index 333e0b6c386..794952d9e04 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -16,7 +16,6 @@ import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.fileTypes.FileTypeManager -import com.intellij.openapi.progress.runBackgroundableTask import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.ex.PathUtilEx @@ -76,6 +75,8 @@ class LoadScriptDefinitionsStartupActivity : StartupActivity { class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinitionProvider() { private var definitionsBySource = mutableMapOf>() + + @Volatile private var definitions: List? = null private val failedContributorsHashes = HashSet() @@ -121,21 +122,26 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = findDefinition(File(fileName).toScriptSource())?.legacyDefinition - fun reloadDefinitionsBy(source: ScriptDefinitionsSource) = lock.write { + fun reloadDefinitionsBy(source: ScriptDefinitionsSource) { if (definitions == null) return // not loaded yet - if (source !in definitionsBySource) error("Unknown script definition source: $source") + lock.write { + if (source !in definitionsBySource) error("Unknown script definition source: $source") + } - definitionsBySource[source] = source.safeGetDefinitions() + val safeGetDefinitions = source.safeGetDefinitions() + lock.write { + definitionsBySource[source] = safeGetDefinitions - definitions = definitionsBySource.values.flattenTo(mutableListOf()) + definitions = definitionsBySource.values.flattenTo(mutableListOf()) - updateDefinitions() + updateDefinitions() + } } override val currentDefinitions get() = - (definitions ?: kotlin.run { + (definitions ?: run { reloadScriptDefinitions() definitions!! }).asSequence().filter { KotlinScriptingSettings.getInstance(project).isScriptDefinitionEnabled(it) } @@ -149,45 +155,46 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit return fromNewEp.dropLast(1) + fromDeprecatedEP + fromNewEp.last() } - fun reloadScriptDefinitionsIfNeeded() = lock.write { - if (definitions == null) { - loadScriptDefinitions() - } + fun reloadScriptDefinitionsIfNeeded() { + definitions ?: loadScriptDefinitions() } - fun reloadScriptDefinitions() = lock.write { - loadScriptDefinitions() - } + fun reloadScriptDefinitions() = loadScriptDefinitions() private fun loadScriptDefinitions() { - for (source in getSources()) { - val definitions = source.safeGetDefinitions() - definitionsBySource[source] = definitions + val newDefinitionsBySource = getSources().map { it to it.safeGetDefinitions() }.toMap() + + lock.write { + definitionsBySource.putAll(newDefinitionsBySource) + definitions = definitionsBySource.values.flattenTo(mutableListOf()) + + updateDefinitions() } - - definitions = definitionsBySource.values.flattenTo(mutableListOf()) - - updateDefinitions() } - fun reorderScriptDefinitions() = lock.write { + fun reorderScriptDefinitions() { definitions?.forEach { - it.order = KotlinScriptingSettings.getInstance(project).getScriptDefinitionOrder(it) + val order = KotlinScriptingSettings.getInstance(project).getScriptDefinitionOrder(it) + lock.write { + it.order = order + } } - definitions = definitions?.sortedBy { it.order } + lock.write { + definitions = definitions?.sortedBy { it.order } - updateDefinitions() + updateDefinitions() + } } - fun getAllDefinitions(): List { - return definitions ?: kotlin.run { - reloadScriptDefinitions() - definitions!! - } + fun getAllDefinitions(): List = definitions ?: run { + reloadScriptDefinitions() + definitions!! } fun isReady(): Boolean { - return definitions != null && definitionsBySource.keys.all { source -> + if (definitions == null) return false + val keys = lock.write { definitionsBySource.keys } + return keys.all { source -> // TODO: implement another API for readiness checking (source as? ScriptDefinitionContributor)?.isReady() != false } diff --git a/idea/src/org/jetbrains/kotlin/idea/script/ScriptTemplatesFromDependenciesProvider.kt b/idea/src/org/jetbrains/kotlin/idea/script/ScriptTemplatesFromDependenciesProvider.kt index 53765d6b844..897a643f15f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/ScriptTemplatesFromDependenciesProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/ScriptTemplatesFromDependenciesProvider.kt @@ -78,6 +78,7 @@ class ScriptTemplatesFromDependenciesProvider(private val project: Project) : Sc } } + @Volatile private var _definitions: List? = null private val definitionsLock = ReentrantLock()