Send roots changed iff combined dependencies of all scripts changed

This reduces total number of reindex requests when working with scripts

ScriptDependenciesCache::onChange logic is independent from ScriptDependenciesUpdater::onChange
This commit is contained in:
Pavel V. Talanov
2017-07-25 15:13:04 +03:00
parent e115c8b373
commit c1fd8fc318
3 changed files with 58 additions and 23 deletions
@@ -16,11 +16,16 @@
package org.jetbrains.kotlin.idea.core.script
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiManager
import com.intellij.psi.search.NonClasspathDirectoriesScope
import kotlinx.coroutines.experimental.launch
import org.jetbrains.kotlin.idea.core.util.EDT
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
@@ -49,7 +54,7 @@ internal class ScriptDependenciesCache(private val project: Project) {
NonClasspathDirectoriesScope(allLibrarySourcesCache.get())
}
fun onChange() {
private fun onChange(file: VirtualFile?) {
allScriptsClasspathCache.clear()
allScriptsClasspathScope.clear()
allLibrarySourcesCache.clear()
@@ -61,11 +66,33 @@ internal class ScriptDependenciesCache(private val project: Project) {
.single()
kotlinScriptDependenciesClassFinder.clearCache()
updateHighlighting(file)
}
private fun updateHighlighting(file: VirtualFile?) {
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
launch(EDT) {
if (file != null) {
file.let { PsiManager.getInstance(project).findFile(it) }?.let { psiFile ->
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
}
}
else {
assert(ApplicationManager.getApplication().isUnitTestMode)
DaemonCodeAnalyzer.getInstance(project).restart()
}
}
}
fun hasNotCachedRoots(scriptDependencies: ScriptDependencies): Boolean {
return !allScriptsClasspathCache.get().containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.classpath)) ||
!allLibrarySourcesCache.get().containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.sources))
}
fun clear() {
cacheLock.write(cache::clear)
onChange()
onChange(null)
}
fun save(virtualFile: VirtualFile, new: ScriptDependencies): Boolean {
@@ -75,11 +102,22 @@ internal class ScriptDependenciesCache(private val project: Project) {
cache[path] = new
old
}
return new != old
val changed = new != old
if (changed) {
onChange(virtualFile)
}
return changed
}
fun delete(virtualFile: VirtualFile): Boolean = cacheLock.write {
cache.remove(virtualFile.path) != null
fun delete(virtualFile: VirtualFile): Boolean {
val changed = cacheLock.write {
cache.remove(virtualFile.path) != null
}
if (changed) {
onChange(virtualFile)
}
return changed
}
}
@@ -89,9 +89,8 @@ class ScriptDependenciesManager internal constructor(
fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) {
with(getInstance(project)) {
val scriptDefinition = KotlinScriptDefinitionProvider.getInstance(project)!!.findScriptDefinition(virtualFile)!!
val updated = cacheUpdater.updateSync(virtualFile, scriptDefinition)
assert(updated)
cacheUpdater.onChange()
cacheUpdater.updateSync(virtualFile, scriptDefinition)
cacheUpdater.notifyRootsChanged()
}
}
@@ -80,8 +80,11 @@ internal class ScriptDependenciesUpdater(
private fun tryLoadingFromDisk(file: VirtualFile) {
ScriptDependenciesFileAttribute.read(file)?.let { deserialized ->
val rootsChanged = cache.hasNotCachedRoots(deserialized)
cache.save(file, deserialized)
onChange()
if (rootsChanged) {
notifyRootsChanged()
}
}
}
@@ -186,8 +189,8 @@ internal class ScriptDependenciesUpdater(
}
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
val resultingDependencies = (result.dependencies ?: ScriptDependencies.Empty).adjustByDefinition(scriptDef)
if (cache(resultingDependencies, file)) {
onChange()
if (saveNewDependencies(resultingDependencies, file)) {
notifyRootsChanged()
}
}
}
@@ -195,26 +198,21 @@ internal class ScriptDependenciesUpdater(
fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean {
val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty
return cache(newDeps, file)
return saveNewDependencies(newDeps, file)
}
private fun cache(
private fun saveNewDependencies(
new: ScriptDependencies,
file: VirtualFile
): Boolean {
val updated = cache.save(file, new)
if (updated) {
val rootsChanged = cache.hasNotCachedRoots(new)
if (cache.save(file, new)) {
ScriptDependenciesFileAttribute.write(file, new)
}
return updated
return rootsChanged
}
fun onChange() {
cache.onChange()
notifyRootsChanged()
}
private fun notifyRootsChanged() {
fun notifyRootsChanged() {
val rootsChangesRunnable = {
runWriteAction {
if (project.isDisposed) return@runWriteAction
@@ -248,7 +246,7 @@ internal class ScriptDependenciesUpdater(
(application.isUnitTestMode || projectFileIndex.isInContent(it)) && !ProjectUtil.isProjectOrWorkspaceFile(it)
}
})) {
onChange()
notifyRootsChanged()
}
}
})