scripting, ucache: don't init caches at start up

init it in async instead. all usages will be updated thanks to
highlighting/reindexing that is called after cache is constructed.

#KT-40242 Fixed
This commit is contained in:
Sergey Rostov
2020-07-17 11:11:12 +03:00
committed by Vladimir Dolzhenko
parent 43fcb2330e
commit b5e04378ed
5 changed files with 43 additions and 33 deletions
@@ -22,7 +22,7 @@ class ScriptClassRootsBuilder(
fun build(): ScriptClassRootsCache = fun build(): ScriptClassRootsCache =
ScriptClassRootsCache( ScriptClassRootsCache(
project, scripts, classes, sources, scripts, classes, sources,
customDefinitionsUsed, sdks.build() customDefinitionsUsed, sdks.build()
) )
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.idea.core.script.ucache package org.jetbrains.kotlin.idea.core.script.ucache
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.OrderRootType import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
@@ -20,15 +19,21 @@ import java.lang.ref.Reference
import java.lang.ref.SoftReference import java.lang.ref.SoftReference
class ScriptClassRootsCache( class ScriptClassRootsCache(
val project: Project,
private val scripts: Map<String, LightScriptInfo>, private val scripts: Map<String, LightScriptInfo>,
private val classes: Set<String>, private val classes: Set<String>,
private val sources: Set<String>, private val sources: Set<String>,
val customDefinitionsUsed: Boolean, val customDefinitionsUsed: Boolean,
val sdks: ScriptSdks val sdks: ScriptSdks
) { ) {
companion object {
val EMPTY = ScriptClassRootsCache(
mapOf(), setOf(), setOf(), true,
ScriptSdks(mapOf(), setOf(), setOf())
)
}
fun withUpdatedSdks(newSdks: ScriptSdks) = fun withUpdatedSdks(newSdks: ScriptSdks) =
ScriptClassRootsCache(project, scripts, classes, sources, customDefinitionsUsed, newSdks) ScriptClassRootsCache(scripts, classes, sources, customDefinitionsUsed, newSdks)
abstract class LightScriptInfo(val definition: ScriptDefinition?) { abstract class LightScriptInfo(val definition: ScriptDefinition?) {
@Volatile @Volatile
@@ -68,11 +68,10 @@ abstract class ScriptClassRootsUpdater(
/** /**
* Wee need CAS due to concurrent unblocking sync update in [checkInvalidSdks] * Wee need CAS due to concurrent unblocking sync update in [checkInvalidSdks]
*/ */
private val cache: AtomicReference<ScriptClassRootsCache> = AtomicReference(recreateRootsCache()) private val cache: AtomicReference<ScriptClassRootsCache> = AtomicReference(ScriptClassRootsCache.EMPTY)
init { init {
@Suppress("LeakingThis") ensureUpdateScheduled()
afterUpdate()
} }
val classpathRoots: ScriptClassRootsCache val classpathRoots: ScriptClassRootsCache
@@ -213,7 +212,7 @@ abstract class ScriptClassRootsUpdater(
// sdks should be updated synchronously to avoid disposed roots usage // sdks should be updated synchronously to avoid disposed roots usage
do { do {
val old = cache.get() val old = cache.get()
val actualSdks = old.sdks.rebuild(remove = remove) val actualSdks = old.sdks.rebuild(project, remove = remove)
if (actualSdks == old.sdks) return if (actualSdks == old.sdks) return
val new = old.withUpdatedSdks(actualSdks) val new = old.withUpdatedSdks(actualSdks)
} while (!cache.compareAndSet(old, new)) } while (!cache.compareAndSet(old, new))
@@ -5,16 +5,16 @@
package org.jetbrains.kotlin.idea.core.script.ucache package org.jetbrains.kotlin.idea.core.script.ucache
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.util.application.runReadAction
class ScriptSdks(val project: Project, private val sdks: Map<SdkId, Sdk?>) { class ScriptSdks(
fun rebuild(remove: Sdk?): ScriptSdks { private val sdks: Map<SdkId, Sdk?>,
val nonIndexedClassRoots: Set<VirtualFile>,
val nonIndexedSourceRoots: Set<VirtualFile>
) {
fun rebuild(project: Project, remove: Sdk?): ScriptSdks {
val builder = ScriptSdksBuilder(project, remove = remove) val builder = ScriptSdksBuilder(project, remove = remove)
sdks.keys.forEach { id -> sdks.keys.forEach { id ->
builder.addSdk(id) builder.addSdk(id)
@@ -22,28 +22,10 @@ class ScriptSdks(val project: Project, private val sdks: Map<SdkId, Sdk?>) {
return builder.build() return builder.build()
} }
val nonIndexedClassRoots = mutableSetOf<VirtualFile>()
val nonIndexedSourceRoots = mutableSetOf<VirtualFile>()
val first: Sdk? = sdks.values.firstOrNull() val first: Sdk? = sdks.values.firstOrNull()
operator fun get(sdkId: SdkId) = sdks[sdkId] operator fun get(sdkId: SdkId) = sdks[sdkId]
init {
val nonIndexedSdks = sdks.values.filterNotNullTo(mutableSetOf())
runReadAction {
ModuleManager.getInstance(project).modules.map {
nonIndexedSdks.remove(ModuleRootManager.getInstance(it).sdk)
}
nonIndexedSdks.forEach {
nonIndexedClassRoots.addAll(it.rootProvider.getFiles(OrderRootType.CLASSES))
nonIndexedSourceRoots.addAll(it.rootProvider.getFiles(OrderRootType.SOURCES))
}
}
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@@ -5,13 +5,18 @@
package org.jetbrains.kotlin.idea.core.script.ucache package org.jetbrains.kotlin.idea.core.script.ucache
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdkType import com.intellij.openapi.projectRoots.JavaSdkType
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsStorage import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsStorage
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.core.script.scriptingWarnLog import org.jetbrains.kotlin.idea.core.script.scriptingWarnLog
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
import java.io.File import java.io.File
@@ -23,7 +28,26 @@ class ScriptSdksBuilder(
) { ) {
private val defaultSdk by lazy { getScriptDefaultSdk() } private val defaultSdk by lazy { getScriptDefaultSdk() }
fun build() = ScriptSdks(project, sdks) fun build(): ScriptSdks {
val nonIndexedClassRoots = mutableSetOf<VirtualFile>()
val nonIndexedSourceRoots = mutableSetOf<VirtualFile>()
val nonIndexedSdks = sdks.values.filterNotNullTo(mutableSetOf())
runReadAction {
for (module in ModuleManager.getInstance(project).modules) {
if (nonIndexedSdks.isEmpty()) break
nonIndexedSdks.remove(ModuleRootManager.getInstance(module).sdk)
}
nonIndexedSdks.forEach {
nonIndexedClassRoots.addAll(it.rootProvider.getFiles(OrderRootType.CLASSES))
nonIndexedSourceRoots.addAll(it.rootProvider.getFiles(OrderRootType.SOURCES))
}
}
return ScriptSdks(sdks, nonIndexedClassRoots, nonIndexedSourceRoots)
}
@Deprecated("Don't use, used only from DefaultScriptingSupport for saving to storage") @Deprecated("Don't use, used only from DefaultScriptingSupport for saving to storage")
fun addAll(other: ScriptSdksBuilder) { fun addAll(other: ScriptSdksBuilder) {