Optimize CoreJrtFileSystem

Do not recompute children on each file request
At the same time, we should clear the roots after each compilation
just the same way as we do for common jars
This commit is contained in:
Denis.Zharkov
2022-12-12 15:00:15 +01:00
committed by Space Team
parent add5fa6e0d
commit d3549c2c5b
3 changed files with 30 additions and 32 deletions
@@ -26,13 +26,11 @@ import java.io.File
import java.net.URI import java.net.URI
import java.net.URLClassLoader import java.net.URLClassLoader
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
// There's JrtFileSystem in idea-full which we can't use in the compiler because it depends on NewVirtualFileSystem, absent in intellij-core // There's JrtFileSystem in idea-full which we can't use in the compiler because it depends on NewVirtualFileSystem, absent in intellij-core
class CoreJrtFileSystem : DeprecatedVirtualFileSystem() { class CoreJrtFileSystem : DeprecatedVirtualFileSystem() {
private val handlers = private val roots =
ConcurrentFactoryMap.createMap<String, CoreJrtHandler?> { jdkHomePath -> ConcurrentFactoryMap.createMap<String, CoreJrtVirtualFile?> { jdkHomePath ->
val jdkHome = File(jdkHomePath) val jdkHome = File(jdkHomePath)
val rootUri = URI.create(StandardFileSystems.JRT_PROTOCOL + ":/") val rootUri = URI.create(StandardFileSystems.JRT_PROTOCOL + ":/")
val jrtFsJar = loadJrtFsJar(jdkHome) ?: return@createMap null val jrtFsJar = loadJrtFsJar(jdkHome) ?: return@createMap null
@@ -50,31 +48,28 @@ class CoreJrtFileSystem : DeprecatedVirtualFileSystem() {
} }
FileSystems.newFileSystem(rootUri, emptyMap<String, Nothing>(), classLoader) FileSystems.newFileSystem(rootUri, emptyMap<String, Nothing>(), classLoader)
} }
CoreJrtHandler(this, jdkHomePath, fileSystem.getPath("")) CoreJrtVirtualFile(this, jdkHomePath, fileSystem.getPath(""), parent = null)
} }
internal class CoreJrtHandler(
val virtualFileSystem: CoreJrtFileSystem,
val jdkHomePath: String,
private val root: Path
) {
fun findFile(fileName: String): VirtualFile? {
val path = root.resolve(fileName)
return if (Files.exists(path)) CoreJrtVirtualFile(this, path) else null
}
}
override fun getProtocol(): String = StandardFileSystems.JRT_PROTOCOL override fun getProtocol(): String = StandardFileSystems.JRT_PROTOCOL
override fun findFileByPath(path: String): VirtualFile? { override fun findFileByPath(path: String): VirtualFile? {
val (jdkHomePath, pathInImage) = splitPath(path) val (jdkHomePath, pathInImage) = splitPath(path)
return handlers[jdkHomePath]?.findFile(pathInImage) val root = roots[jdkHomePath] ?: return null
if (pathInImage.isEmpty()) return root
return root.findFileByRelativePath(pathInImage)
} }
override fun refresh(asynchronous: Boolean) {} override fun refresh(asynchronous: Boolean) {}
override fun refreshAndFindFileByPath(path: String): VirtualFile? = findFileByPath(path) override fun refreshAndFindFileByPath(path: String): VirtualFile? = findFileByPath(path)
fun clearRoots() {
roots.clear()
}
companion object { companion object {
private fun loadJrtFsJar(jdkHome: File): File? = private fun loadJrtFsJar(jdkHome: File): File? =
File(jdkHome, "lib/jrt-fs.jar").takeIf(File::exists) File(jdkHome, "lib/jrt-fs.jar").takeIf(File::exists)
@@ -21,7 +21,6 @@ import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileSystem import com.intellij.openapi.vfs.VirtualFileSystem
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem.CoreJrtHandler
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
@@ -29,17 +28,22 @@ import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
internal class CoreJrtVirtualFile(private val handler: CoreJrtHandler, private val path: Path) : VirtualFile() { internal class CoreJrtVirtualFile(
private val virtualFileSystem: CoreJrtFileSystem,
private val jdkHomePath: String,
private val path: Path,
private val parent: CoreJrtVirtualFile?,
) : VirtualFile() {
// TODO: catch IOException? // TODO: catch IOException?
private val attributes: BasicFileAttributes get() = Files.readAttributes(path, BasicFileAttributes::class.java) private val attributes: BasicFileAttributes get() = Files.readAttributes(path, BasicFileAttributes::class.java)
override fun getFileSystem(): VirtualFileSystem = handler.virtualFileSystem override fun getFileSystem(): VirtualFileSystem = virtualFileSystem
override fun getName(): String = override fun getName(): String =
path.fileName.toString() path.fileName.toString()
override fun getPath(): String = override fun getPath(): String =
FileUtil.toSystemIndependentName(handler.jdkHomePath + URLUtil.JAR_SEPARATOR + path) FileUtil.toSystemIndependentName(jdkHomePath + URLUtil.JAR_SEPARATOR + path)
override fun isWritable(): Boolean = false override fun isWritable(): Boolean = false
@@ -47,20 +51,21 @@ internal class CoreJrtVirtualFile(private val handler: CoreJrtHandler, private v
override fun isValid(): Boolean = true override fun isValid(): Boolean = true
override fun getParent(): VirtualFile? { override fun getParent(): VirtualFile? = parent
val parentPath = path.parent
return if (parentPath != null) CoreJrtVirtualFile(handler, parentPath) else null
}
override fun getChildren(): Array<out VirtualFile> { private val myChildren by lazy { computeChildren() }
override fun getChildren(): Array<out VirtualFile> = myChildren
private fun computeChildren(): Array<out VirtualFile> {
val paths = try { val paths = try {
Files.newDirectoryStream(path).use(Iterable<Path>::toList) Files.newDirectoryStream(path).use(Iterable<Path>::toList)
} catch (e: IOException) { } catch (e: IOException) {
emptyList<Path>() emptyList<Path>()
} }
return when { return when {
paths.isEmpty() -> VirtualFile.EMPTY_ARRAY paths.isEmpty() -> EMPTY_ARRAY
else -> paths.map { path -> CoreJrtVirtualFile(handler, path) }.toTypedArray() else -> paths.map { path -> CoreJrtVirtualFile(virtualFileSystem, jdkHomePath, path, parent = this) }.toTypedArray()
} }
} }
@@ -32,17 +32,16 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.cli.js.K2JSCompiler import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.* import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.report.CompileServicesFacadeMessageCollector import org.jetbrains.kotlin.daemon.report.CompileServicesFacadeMessageCollector
import org.jetbrains.kotlin.daemon.report.DaemonMessageReporter import org.jetbrains.kotlin.daemon.report.DaemonMessageReporter
import org.jetbrains.kotlin.daemon.report.DaemonMessageReporterPrintStreamAdapter
import org.jetbrains.kotlin.daemon.report.getBuildReporter import org.jetbrains.kotlin.daemon.report.getBuildReporter
import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
@@ -57,9 +56,7 @@ import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
import org.jetbrains.kotlin.incremental.parsing.classesFqNames import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.PrintStream
import java.rmi.NoSuchObjectException import java.rmi.NoSuchObjectException
import java.rmi.registry.Registry import java.rmi.registry.Registry
import java.rmi.server.UnicastRemoteObject import java.rmi.server.UnicastRemoteObject
@@ -1073,6 +1070,7 @@ class CompileServiceImpl(
ZipHandler.clearFileAccessorCache() ZipHandler.clearFileAccessorCache()
KotlinCoreEnvironment.applicationEnvironment?.apply { KotlinCoreEnvironment.applicationEnvironment?.apply {
(jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache() (jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
(jrtFileSystem as? CoreJrtFileSystem)?.clearRoots()
idleCleanup() idleCleanup()
} }
} }