Split script configuration state into applied and loaded to make markUpToDate more clear
This commit is contained in:
committed by
Natalia Selezneva
parent
fde1d3fdf7
commit
fbb2b260dd
+18
-15
@@ -20,9 +20,9 @@ import kotlinx.coroutines.launch
|
|||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.idea.core.script.*
|
import org.jetbrains.kotlin.idea.core.script.*
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.toVfsRoots
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.toVfsRoots
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
|
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCache
|
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCache
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
|
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
|
||||||
|
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationState
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache
|
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsIndexer
|
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsIndexer
|
||||||
@@ -40,7 +40,7 @@ import kotlin.concurrent.withLock
|
|||||||
* Among this two methods concrete implementation should provide script changes listening (by calling [updater] on some event).
|
* Among this two methods concrete implementation should provide script changes listening (by calling [updater] on some event).
|
||||||
*
|
*
|
||||||
* Basically all requests routed to [cache]. If there is no entry in [cache] or it is considered out-of-date,
|
* Basically all requests routed to [cache]. If there is no entry in [cache] or it is considered out-of-date,
|
||||||
* then [reloadOutOfDateConfiguration] will be called, which, in turn, should call [saveChangedConfiguration]
|
* then [reloadOutOfDateConfiguration] will be called, which, in turn, should call [setAppliedConfiguration]
|
||||||
* immediately or in some future (e.g. after user will click "apply context" or/and configuration will
|
* immediately or in some future (e.g. after user will click "apply context" or/and configuration will
|
||||||
* be calculated by some background thread).
|
* be calculated by some background thread).
|
||||||
*
|
*
|
||||||
@@ -61,7 +61,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be called on [cache] miss or when [file] is changed.
|
* Will be called on [cache] miss or when [file] is changed.
|
||||||
* Implementation should initiate loading of [file]'s script configuration and call [saveChangedConfiguration]
|
* Implementation should initiate loading of [file]'s script configuration and call [setAppliedConfiguration]
|
||||||
* immediately or in some future
|
* immediately or in some future
|
||||||
* (e.g. after user will click "apply context" or/and configuration will be calculated by some background thread).
|
* (e.g. after user will click "apply context" or/and configuration will be calculated by some background thread).
|
||||||
*
|
*
|
||||||
@@ -73,7 +73,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
*/
|
*/
|
||||||
protected abstract fun reloadOutOfDateConfiguration(
|
protected abstract fun reloadOutOfDateConfiguration(
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
isFirstLoad: Boolean = getCachedConfiguration(file.originalFile.virtualFile) == null,
|
isFirstLoad: Boolean = getAppliedConfiguration(file.originalFile.virtualFile) == null,
|
||||||
loadEvenWillNotBeApplied: Boolean = false,
|
loadEvenWillNotBeApplied: Boolean = false,
|
||||||
forceSync: Boolean = false
|
forceSync: Boolean = false
|
||||||
)
|
)
|
||||||
@@ -87,13 +87,16 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
override fun getScriptClasspath(file: KtFile): List<VirtualFile> =
|
override fun getScriptClasspath(file: KtFile): List<VirtualFile> =
|
||||||
toVfsRoots(getConfiguration(file)?.dependenciesClassPath.orEmpty())
|
toVfsRoots(getConfiguration(file)?.dependenciesClassPath.orEmpty())
|
||||||
|
|
||||||
fun getCachedConfiguration(file: VirtualFile?): ScriptConfigurationSnapshot? {
|
fun getCachedConfigurationState(file: VirtualFile?): ScriptConfigurationState? {
|
||||||
if (file == null) return null
|
if (file == null) return null
|
||||||
return cache[file]
|
return cache[file]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAppliedConfiguration(file: VirtualFile?): ScriptConfigurationSnapshot? =
|
||||||
|
getCachedConfigurationState(file)?.applied
|
||||||
|
|
||||||
override fun hasConfiguration(file: KtFile): Boolean {
|
override fun hasConfiguration(file: KtFile): Boolean {
|
||||||
return getCachedConfiguration(file.originalFile.virtualFile) != null
|
return getAppliedConfiguration(file.originalFile.virtualFile) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? {
|
override fun getConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? {
|
||||||
@@ -104,7 +107,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
virtualFile: VirtualFile,
|
virtualFile: VirtualFile,
|
||||||
preloadedKtFile: KtFile? = null
|
preloadedKtFile: KtFile? = null
|
||||||
): ScriptCompilationConfigurationWrapper? {
|
): ScriptCompilationConfigurationWrapper? {
|
||||||
val cached = getCachedConfiguration(virtualFile)
|
val cached = getAppliedConfiguration(virtualFile)
|
||||||
if (cached != null) return cached.configuration
|
if (cached != null) return cached.configuration
|
||||||
|
|
||||||
val ktFile = project.getKtFile(virtualFile, preloadedKtFile) ?: return null
|
val ktFile = project.getKtFile(virtualFile, preloadedKtFile) ?: return null
|
||||||
@@ -112,7 +115,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
reloadOutOfDateConfiguration(ktFile, isFirstLoad = true)
|
reloadOutOfDateConfiguration(ktFile, isFirstLoad = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getCachedConfiguration(virtualFile)?.configuration
|
return getAppliedConfiguration(virtualFile)?.configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
override val updater: ScriptConfigurationUpdater = object : ScriptConfigurationUpdater {
|
override val updater: ScriptConfigurationUpdater = object : ScriptConfigurationUpdater {
|
||||||
@@ -143,7 +146,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
val virtualFile = file.originalFile.virtualFile
|
val virtualFile = file.originalFile.virtualFile
|
||||||
if (virtualFile != null) {
|
if (virtualFile != null) {
|
||||||
val state = cache[virtualFile]
|
val state = cache[virtualFile]
|
||||||
if (state == null || !state.inputs.isUpToDate(project, virtualFile, file)) {
|
if (state == null || !state.isUpToDate(project, virtualFile, file)) {
|
||||||
upToDate = false
|
upToDate = false
|
||||||
reloadOutOfDateConfiguration(
|
reloadOutOfDateConfiguration(
|
||||||
file,
|
file,
|
||||||
@@ -165,14 +168,14 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
file as? KtFile ?: error("PsiFile $file should be a KtFile, otherwise script dependencies cannot be loaded")
|
file as? KtFile ?: error("PsiFile $file should be a KtFile, otherwise script dependencies cannot be loaded")
|
||||||
|
|
||||||
val virtualFile = file.virtualFile
|
val virtualFile = file.virtualFile
|
||||||
if (cache[virtualFile]?.inputs?.isUpToDate(project, virtualFile, file) == true) return
|
if (cache[virtualFile]?.isUpToDate(project, virtualFile, file) == true) return
|
||||||
|
|
||||||
rootsIndexer.transaction {
|
rootsIndexer.transaction {
|
||||||
reloadOutOfDateConfiguration(file, isFirstLoad = true, forceSync = true)
|
reloadOutOfDateConfiguration(file, isFirstLoad = true, forceSync = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun saveChangedConfiguration(
|
protected open fun setAppliedConfiguration(
|
||||||
file: VirtualFile,
|
file: VirtualFile,
|
||||||
newConfigurationSnapshot: ScriptConfigurationSnapshot?
|
newConfigurationSnapshot: ScriptConfigurationSnapshot?
|
||||||
) {
|
) {
|
||||||
@@ -185,7 +188,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
rootsIndexer.markNewRoot(file, newConfiguration)
|
rootsIndexer.markNewRoot(file, newConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
cache[file] = newConfigurationSnapshot
|
cache.setApplied(file, newConfigurationSnapshot)
|
||||||
|
|
||||||
clearClassRootsCaches()
|
clearClassRootsCaches()
|
||||||
}
|
}
|
||||||
@@ -193,11 +196,11 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
updateHighlighting(listOf(file))
|
updateHighlighting(listOf(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun markUpToDate(
|
protected fun setLoadedConfiguration(
|
||||||
file: VirtualFile,
|
file: VirtualFile,
|
||||||
inputs: CachedConfigurationInputs
|
configurationSnapshot: ScriptConfigurationSnapshot
|
||||||
) {
|
) {
|
||||||
cache.markUpToDate(file, inputs)
|
cache.setLoaded(file, configurationSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasNotCachedRoots(configuration: ScriptCompilationConfigurationWrapper): Boolean {
|
private fun hasNotCachedRoots(configuration: ScriptCompilationConfigurationWrapper): Boolean {
|
||||||
|
|||||||
+8
-8
@@ -141,7 +141,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
* and file will be up-to-date checked again. This will happen after current loading,
|
* and file will be up-to-date checked again. This will happen after current loading,
|
||||||
* because only `backgroundExecutor` execute tasks in one thread.
|
* because only `backgroundExecutor` execute tasks in one thread.
|
||||||
* - `invalid, waiting for apply`:
|
* - `invalid, waiting for apply`:
|
||||||
* Loading will not be queued, since we are marking file is up to date with
|
* Loading will not be queued, since we are marking file as up-to-date with
|
||||||
* not yet applied configuration.
|
* not yet applied configuration.
|
||||||
*
|
*
|
||||||
* Sync:
|
* Sync:
|
||||||
@@ -177,8 +177,8 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
backgroundExecutor.ensureScheduled(virtualFile) {
|
backgroundExecutor.ensureScheduled(virtualFile) {
|
||||||
// don't start loading if nothing was changed
|
// don't start loading if nothing was changed
|
||||||
// (in case we checking for up-to-date and loading concurrently)
|
// (in case we checking for up-to-date and loading concurrently)
|
||||||
val cached = getCachedConfiguration(virtualFile)
|
val cached = getCachedConfigurationState(virtualFile)
|
||||||
if (cached == null || !cached.inputs.isUpToDate(project, virtualFile)) {
|
if (cached == null || !cached.isUpToDate(project, virtualFile)) {
|
||||||
val actualIsFirstLoad = cached == null
|
val actualIsFirstLoad = cached == null
|
||||||
async.first { it.loadDependencies(actualIsFirstLoad, virtualFile, scriptDefinition, loadingContext) }
|
async.first { it.loadDependencies(actualIsFirstLoad, virtualFile, scriptDefinition, loadingContext) }
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
|
|
||||||
private val loadingContext = object : ScriptConfigurationLoadingContext {
|
private val loadingContext = object : ScriptConfigurationLoadingContext {
|
||||||
override fun getCachedConfiguration(file: VirtualFile): ScriptConfigurationSnapshot? =
|
override fun getCachedConfiguration(file: VirtualFile): ScriptConfigurationSnapshot? =
|
||||||
this@DefaultScriptConfigurationManager.getCachedConfiguration(file)
|
this@DefaultScriptConfigurationManager.getAppliedConfiguration(file)
|
||||||
|
|
||||||
override fun suggestNewConfiguration(file: VirtualFile, newResult: ScriptConfigurationSnapshot) {
|
override fun suggestNewConfiguration(file: VirtualFile, newResult: ScriptConfigurationSnapshot) {
|
||||||
suggestOrSaveConfiguration(file, newResult, false)
|
suggestOrSaveConfiguration(file, newResult, false)
|
||||||
@@ -221,13 +221,13 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
saveLock.withLock {
|
saveLock.withLock {
|
||||||
debug(file) { "configuration received = $newResult" }
|
debug(file) { "configuration received = $newResult" }
|
||||||
|
|
||||||
markUpToDate(file, newResult.inputs)
|
setLoadedConfiguration(file, newResult)
|
||||||
|
|
||||||
val newConfiguration = newResult.configuration
|
val newConfiguration = newResult.configuration
|
||||||
if (newConfiguration == null) {
|
if (newConfiguration == null) {
|
||||||
saveReports(file, newResult.reports)
|
saveReports(file, newResult.reports)
|
||||||
} else {
|
} else {
|
||||||
val oldConfiguration = getCachedConfiguration(file)?.configuration
|
val oldConfiguration = getAppliedConfiguration(file)?.configuration
|
||||||
if (oldConfiguration == newConfiguration) {
|
if (oldConfiguration == newConfiguration) {
|
||||||
saveReports(file, newResult.reports)
|
saveReports(file, newResult.reports)
|
||||||
file.removeScriptDependenciesNotificationPanel(project)
|
file.removeScriptDependenciesNotificationPanel(project)
|
||||||
@@ -242,7 +242,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
file.removeScriptDependenciesNotificationPanel(project)
|
file.removeScriptDependenciesNotificationPanel(project)
|
||||||
}
|
}
|
||||||
saveReports(file, newResult.reports)
|
saveReports(file, newResult.reports)
|
||||||
saveChangedConfiguration(file, newResult)
|
setAppliedConfiguration(file, newResult)
|
||||||
} else {
|
} else {
|
||||||
debug(file) {
|
debug(file) {
|
||||||
"configuration changed, notification is shown: old = $oldConfiguration, new = $newConfiguration"
|
"configuration changed, notification is shown: old = $oldConfiguration, new = $newConfiguration"
|
||||||
@@ -253,7 +253,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
saveReports(file, newResult.reports)
|
saveReports(file, newResult.reports)
|
||||||
file.removeScriptDependenciesNotificationPanel(project)
|
file.removeScriptDependenciesNotificationPanel(project)
|
||||||
rootsIndexer.transaction {
|
rootsIndexer.transaction {
|
||||||
saveChangedConfiguration(file, newResult)
|
setAppliedConfiguration(file, newResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
+13
-5
@@ -30,6 +30,14 @@ data class ScriptConfigurationSnapshot(
|
|||||||
val configuration: ScriptCompilationConfigurationWrapper?
|
val configuration: ScriptCompilationConfigurationWrapper?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class ScriptConfigurationState(
|
||||||
|
val applied: ScriptConfigurationSnapshot? = null,
|
||||||
|
val loaded: ScriptConfigurationSnapshot? = null
|
||||||
|
) {
|
||||||
|
fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile? = null): Boolean =
|
||||||
|
(loaded ?: applied)?.inputs?.isUpToDate(project, file, ktFile) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached configurations for file's specific snapshot state.
|
* Cached configurations for file's specific snapshot state.
|
||||||
*
|
*
|
||||||
@@ -37,11 +45,11 @@ data class ScriptConfigurationSnapshot(
|
|||||||
* Reader may do up-to-date check for existed entry.
|
* Reader may do up-to-date check for existed entry.
|
||||||
*/
|
*/
|
||||||
interface ScriptConfigurationCache {
|
interface ScriptConfigurationCache {
|
||||||
operator fun get(file: VirtualFile): ScriptConfigurationSnapshot?
|
operator fun get(file: VirtualFile): ScriptConfigurationState?
|
||||||
operator fun set(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot)
|
|
||||||
|
|
||||||
fun markUpToDate(file: VirtualFile, inputs: CachedConfigurationInputs)
|
fun setApplied(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot)
|
||||||
fun markOutOfDate(file: VirtualFile) = markUpToDate(file, CachedConfigurationInputs.OutOfDate)
|
fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot)
|
||||||
|
fun markOutOfDate(file: VirtualFile)
|
||||||
|
|
||||||
fun all(): Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>>
|
fun allApplied(): Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>>
|
||||||
}
|
}
|
||||||
+24
-17
@@ -17,34 +17,41 @@ class ScriptConfigurationMemoryCache(
|
|||||||
const val MAX_SCRIPTS_CACHED = 50
|
const val MAX_SCRIPTS_CACHED = 50
|
||||||
}
|
}
|
||||||
|
|
||||||
private val memoryCache = SLRUMap<VirtualFile, ScriptConfigurationSnapshot>(MAX_SCRIPTS_CACHED, MAX_SCRIPTS_CACHED)
|
private val memoryCache = SLRUMap<VirtualFile, ScriptConfigurationState>(MAX_SCRIPTS_CACHED, MAX_SCRIPTS_CACHED)
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override operator fun get(file: VirtualFile): ScriptConfigurationSnapshot? {
|
override operator fun get(file: VirtualFile): ScriptConfigurationState? {
|
||||||
return memoryCache.get(file)
|
return memoryCache.get(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override operator fun set(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
override fun setApplied(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
||||||
memoryCache.put(
|
val old = memoryCache[file] ?: ScriptConfigurationState()
|
||||||
file,
|
memoryCache.put(file, old.copy(applied = configurationSnapshot))
|
||||||
configurationSnapshot
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markUpToDate(file: VirtualFile, inputs: CachedConfigurationInputs) {
|
@Synchronized
|
||||||
val old = memoryCache[file]
|
override fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
||||||
if (old != null) {
|
val old = memoryCache[file] ?: ScriptConfigurationState()
|
||||||
memoryCache.put(file, old.copy(inputs = inputs))
|
memoryCache.put(file, old.copy(loaded = configurationSnapshot))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun markOutOfDate(file: VirtualFile) {
|
||||||
|
val old = memoryCache[file] ?: ScriptConfigurationState()
|
||||||
|
memoryCache.put(
|
||||||
|
file, old.copy(
|
||||||
|
applied = old.applied?.copy(inputs = CachedConfigurationInputs.OutOfDate),
|
||||||
|
loaded = old.loaded?.copy(inputs = CachedConfigurationInputs.OutOfDate)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun all() =
|
override fun allApplied() =
|
||||||
memoryCache.entrySet().map {
|
memoryCache.entrySet().mapNotNull {
|
||||||
if (it.value.configuration == null) null
|
if (it.value.applied?.configuration == null) null
|
||||||
else it.key to it.value.configuration
|
else it.key to it.value.applied?.configuration
|
||||||
} as Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>>
|
} as Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>>
|
||||||
}
|
}
|
||||||
+2
-2
@@ -25,8 +25,8 @@ internal class ScriptClassRootsCache(
|
|||||||
private val project: Project,
|
private val project: Project,
|
||||||
private val cache: ScriptConfigurationCache
|
private val cache: ScriptConfigurationCache
|
||||||
) {
|
) {
|
||||||
private val all: Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>> get() = cache.all()
|
private val all: Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>> get() = cache.allApplied()
|
||||||
private fun getConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? = cache[file]?.configuration
|
private fun getConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? = cache[file]?.applied?.configuration
|
||||||
|
|
||||||
private fun getScriptSdk(compilationConfiguration: ScriptCompilationConfigurationWrapper?): Sdk? {
|
private fun getScriptSdk(compilationConfiguration: ScriptCompilationConfigurationWrapper?): Sdk? {
|
||||||
// workaround for mismatched gradle wrapper and plugin version
|
// workaround for mismatched gradle wrapper and plugin version
|
||||||
|
|||||||
Reference in New Issue
Block a user