[K/N] Proper invalidation of metadata cache in IDEA by VFS events
This commit is contained in:
committed by
Simon Ogorodnik
parent
35a0b42796
commit
db418123d4
+30
-11
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ide.konan.decompiler
|
|||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.components.ApplicationComponent
|
import com.intellij.openapi.components.ApplicationComponent
|
||||||
import com.intellij.openapi.vfs.*
|
import com.intellij.openapi.vfs.*
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore.isEqualOrAncestor
|
||||||
import com.intellij.util.containers.ContainerUtil.createConcurrentSoftValueMap
|
import com.intellij.util.containers.ContainerUtil.createConcurrentSoftValueMap
|
||||||
import org.jetbrains.kotlin.konan.library.KLIB_METADATA_FILE_EXTENSION
|
import org.jetbrains.kotlin.konan.library.KLIB_METADATA_FILE_EXTENSION
|
||||||
import org.jetbrains.kotlin.konan.library.KLIB_MODULE_METADATA_FILE_NAME
|
import org.jetbrains.kotlin.konan.library.KLIB_MODULE_METADATA_FILE_NAME
|
||||||
@@ -23,17 +24,17 @@ class KotlinNativeLoadingMetadataCache : ApplicationComponent {
|
|||||||
ApplicationManager.getApplication().getComponent(KotlinNativeLoadingMetadataCache::class.java)
|
ApplicationManager.getApplication().getComponent(KotlinNativeLoadingMetadataCache::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val packageFragmentCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataPackageFragment>()
|
private val packageFragmentCache = createConcurrentSoftValueMap<String, KonanProtoBuf.LinkDataPackageFragment>()
|
||||||
private val moduleHeaderCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataLibrary>()
|
private val moduleHeaderCache = createConcurrentSoftValueMap<String, KonanProtoBuf.LinkDataLibrary>()
|
||||||
|
|
||||||
fun getCachedPackageFragment(virtualFile: VirtualFile): KonanProtoBuf.LinkDataPackageFragment =
|
fun getCachedPackageFragment(virtualFile: VirtualFile): KonanProtoBuf.LinkDataPackageFragment =
|
||||||
packageFragmentCache.computeIfAbsent(virtualFile.surePackageMetadataFile) {
|
packageFragmentCache.computeIfAbsent(virtualFile.ensurePackageMetadataFile.url) {
|
||||||
parsePackageFragment(virtualFile.contentsToByteArray(false))
|
virtualFile.createPackageFragmentCacheEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCachedModuleHeader(virtualFile: VirtualFile): KonanProtoBuf.LinkDataLibrary =
|
fun getCachedModuleHeader(virtualFile: VirtualFile): KonanProtoBuf.LinkDataLibrary =
|
||||||
moduleHeaderCache.computeIfAbsent(virtualFile.sureModuleHeaderFile) {
|
moduleHeaderCache.computeIfAbsent(virtualFile.ensureModuleHeaderFile.url) {
|
||||||
parseModuleHeader(virtualFile.contentsToByteArray(false))
|
virtualFile.createModuleHeaderCacheEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initComponent() {
|
override fun initComponent() {
|
||||||
@@ -46,20 +47,38 @@ class KotlinNativeLoadingMetadataCache : ApplicationComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invalidateCaches(virtualFile: VirtualFile) {
|
private fun invalidateCaches(modifiedFile: VirtualFile) {
|
||||||
when {
|
when {
|
||||||
virtualFile.isPackageMetadataFile -> packageFragmentCache.remove(virtualFile)
|
modifiedFile.isPackageMetadataFile -> packageFragmentCache.remove(modifiedFile.url)
|
||||||
virtualFile.isModuleHeaderFile -> moduleHeaderCache.remove(virtualFile)
|
modifiedFile.isModuleHeaderFile -> moduleHeaderCache.remove(modifiedFile.url)
|
||||||
|
modifiedFile.isDirectory -> {
|
||||||
|
val ancestorUrl = modifiedFile.url
|
||||||
|
packageFragmentCache.removeDescendants(ancestorUrl)
|
||||||
|
moduleHeaderCache.removeDescendants(ancestorUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val VirtualFile.surePackageMetadataFile
|
private fun <V> MutableMap<String, V>.removeDescendants(ancestorUrl: String) {
|
||||||
|
|
||||||
|
// Warning: Do not try to apply ".removeIf {}" to "entries". This will have no effect to
|
||||||
|
// the Map produced by ContainerUtil.createConcurrentSoftValueMap().
|
||||||
|
keys.removeIf { descendantCandidateUrl -> isEqualOrAncestor(ancestorUrl, descendantCandidateUrl) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val VirtualFile.createPackageFragmentCacheEntry
|
||||||
|
get() = parsePackageFragment(contentsToByteArray(false))
|
||||||
|
|
||||||
|
private val VirtualFile.createModuleHeaderCacheEntry
|
||||||
|
get() = parseModuleHeader(contentsToByteArray(false))
|
||||||
|
|
||||||
|
private val VirtualFile.ensurePackageMetadataFile
|
||||||
get() = if (isPackageMetadataFile) this else error("Not a package metadata file: $this")
|
get() = if (isPackageMetadataFile) this else error("Not a package metadata file: $this")
|
||||||
|
|
||||||
private val VirtualFile.isPackageMetadataFile
|
private val VirtualFile.isPackageMetadataFile
|
||||||
get() = extension == KLIB_METADATA_FILE_EXTENSION
|
get() = extension == KLIB_METADATA_FILE_EXTENSION
|
||||||
|
|
||||||
private val VirtualFile.sureModuleHeaderFile
|
private val VirtualFile.ensureModuleHeaderFile
|
||||||
get() = if (isModuleHeaderFile) this else error("Not a module header file: $this")
|
get() = if (isModuleHeaderFile) this else error("Not a module header file: $this")
|
||||||
|
|
||||||
private val VirtualFile.isModuleHeaderFile
|
private val VirtualFile.isModuleHeaderFile
|
||||||
|
|||||||
Reference in New Issue
Block a user