Move handlers cache from static field to the instance of FastJarFileSystem
This commit is contained in:
committed by
TeamCityServer
parent
03e5dc6117
commit
c6525974d0
@@ -539,7 +539,7 @@ class KotlinCoreEnvironment private constructor(
|
|||||||
ourApplicationEnvironment = null
|
ourApplicationEnvironment = null
|
||||||
Disposer.dispose(environment.parentDisposable)
|
Disposer.dispose(environment.parentDisposable)
|
||||||
ZipHandler.clearFileAccessorCache()
|
ZipHandler.clearFileAccessorCache()
|
||||||
FastJarHandler.cleanFileAccessorsCache()
|
(environment.jarFileSystem as? FastJarFileSystem)?.clearHandlersCache()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,39 @@ import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem
|
|||||||
import com.intellij.openapi.vfs.StandardFileSystems
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||||
|
import com.intellij.util.io.FileAccessorCache
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.MappedByteBuffer
|
||||||
|
import java.nio.channels.FileChannel
|
||||||
|
|
||||||
|
private typealias RandomAccessFileAndBuffer = Pair<RandomAccessFile, MappedByteBuffer>
|
||||||
|
|
||||||
class FastJarFileSystem : DeprecatedVirtualFileSystem() {
|
class FastJarFileSystem : DeprecatedVirtualFileSystem() {
|
||||||
private val myHandlers: MutableMap<String, FastJarHandler> =
|
private val myHandlers: MutableMap<String, FastJarHandler> =
|
||||||
ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) }
|
ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) }
|
||||||
|
|
||||||
|
internal val cachedOpenFileHandles: FileAccessorCache<File, RandomAccessFileAndBuffer> =
|
||||||
|
object : FileAccessorCache<File, RandomAccessFileAndBuffer>(20, 10) {
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun createAccessor(file: File): RandomAccessFileAndBuffer {
|
||||||
|
val randomAccessFile = RandomAccessFile(file, "r")
|
||||||
|
return Pair(randomAccessFile, randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun disposeAccessor(fileAccessor: RandomAccessFileAndBuffer) {
|
||||||
|
fileAccessor.first.close()
|
||||||
|
fileAccessor.second.unmapBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEqual(val1: File, val2: File): Boolean {
|
||||||
|
return val1 == val2 // reference equality to handle different jars for different ZipHandlers on the same path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getProtocol(): String {
|
override fun getProtocol(): String {
|
||||||
return StandardFileSystems.JAR_PROTOCOL
|
return StandardFileSystems.JAR_PROTOCOL
|
||||||
}
|
}
|
||||||
@@ -30,6 +58,7 @@ class FastJarFileSystem : DeprecatedVirtualFileSystem() {
|
|||||||
|
|
||||||
fun clearHandlersCache() {
|
fun clearHandlersCache() {
|
||||||
myHandlers.clear()
|
myHandlers.clear()
|
||||||
|
cachedOpenFileHandles.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -42,3 +71,42 @@ class FastJarFileSystem : DeprecatedVirtualFileSystem() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val IS_PRIOR_9_JRE = System.getProperty("java.specification.version", "").startsWith("1.")
|
||||||
|
|
||||||
|
internal fun ByteBuffer.unmapBuffer() {
|
||||||
|
if (!isDirect) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (IS_PRIOR_9_JRE) {
|
||||||
|
val cleaner = this::class.java.getMethod("cleaner")
|
||||||
|
|
||||||
|
cleaner.isAccessible = true
|
||||||
|
|
||||||
|
val clean = Class.forName("sun.misc.Cleaner").getMethod("clean")
|
||||||
|
clean.isAccessible = true
|
||||||
|
|
||||||
|
clean.invoke(cleaner.invoke(this))
|
||||||
|
} else {
|
||||||
|
val unsafeClass = try {
|
||||||
|
Class.forName("sun.misc.Unsafe")
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
// jdk.internal.misc.Unsafe doesn't yet have an invokeCleaner() method,
|
||||||
|
// but that method should be added if sun.misc.Unsafe is removed.
|
||||||
|
Class.forName("jdk.internal.misc.Unsafe")
|
||||||
|
}
|
||||||
|
|
||||||
|
val clean = unsafeClass.getMethod("invokeCleaner", ByteBuffer::class.java)
|
||||||
|
clean.isAccessible = true
|
||||||
|
|
||||||
|
val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe")
|
||||||
|
theUnsafeField.isAccessible = true
|
||||||
|
|
||||||
|
val theUnsafe = theUnsafeField.get(null)
|
||||||
|
|
||||||
|
clean.invoke(theUnsafe, this)
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -143,77 +143,14 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl
|
|||||||
override fun contentsToByteArray(relativePath: String): ByteArray {
|
override fun contentsToByteArray(relativePath: String): ByteArray {
|
||||||
if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
|
if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
|
||||||
val zipEntryDescription = ourEntryMap[relativePath] ?: throw FileNotFoundException("$file!/$relativePath")
|
val zipEntryDescription = ourEntryMap[relativePath] ?: throw FileNotFoundException("$file!/$relativePath")
|
||||||
return cachedOpenFileHandles[file].use {
|
return fileSystem.cachedOpenFileHandles[file].use {
|
||||||
synchronized(it) {
|
synchronized(it) {
|
||||||
it.get().second.contentsToByteArray(zipEntryDescription)
|
it.get().second.contentsToByteArray(zipEntryDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun cleanFileAccessorsCache() {
|
|
||||||
cachedOpenFileHandles.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
|
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
|
||||||
|
|
||||||
typealias RandomAccessFileAndBuffer = Pair<RandomAccessFile, MappedByteBuffer>
|
|
||||||
|
|
||||||
private val cachedOpenFileHandles: FileAccessorCache<File, RandomAccessFileAndBuffer> =
|
|
||||||
object : FileAccessorCache<File, RandomAccessFileAndBuffer>(20, 10) {
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createAccessor(file: File): RandomAccessFileAndBuffer {
|
|
||||||
val randomAccessFile = RandomAccessFile(file, "r")
|
|
||||||
return Pair(randomAccessFile, randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun disposeAccessor(fileAccessor: RandomAccessFileAndBuffer) {
|
|
||||||
fileAccessor.first.close()
|
|
||||||
fileAccessor.second.unmapBuffer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEqual(val1: File, val2: File): Boolean {
|
|
||||||
return val1 == val2 // reference equality to handle different jars for different ZipHandlers on the same path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val IS_PRIOR_9_JRE = System.getProperty("java.specification.version", "").startsWith("1.")
|
|
||||||
|
|
||||||
private fun ByteBuffer.unmapBuffer() {
|
|
||||||
if (!isDirect) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (IS_PRIOR_9_JRE) {
|
|
||||||
val cleaner = this::class.java.getMethod("cleaner")
|
|
||||||
|
|
||||||
cleaner.isAccessible = true
|
|
||||||
|
|
||||||
val clean = Class.forName("sun.misc.Cleaner").getMethod("clean")
|
|
||||||
clean.isAccessible = true
|
|
||||||
|
|
||||||
clean.invoke(cleaner.invoke(this))
|
|
||||||
} else {
|
|
||||||
val unsafeClass = try {
|
|
||||||
Class.forName("sun.misc.Unsafe")
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
// jdk.internal.misc.Unsafe doesn't yet have an invokeCleaner() method,
|
|
||||||
// but that method should be added if sun.misc.Unsafe is removed.
|
|
||||||
Class.forName("jdk.internal.misc.Unsafe")
|
|
||||||
}
|
|
||||||
|
|
||||||
val clean = unsafeClass.getMethod("invokeCleaner", ByteBuffer::class.java)
|
|
||||||
clean.isAccessible = true
|
|
||||||
|
|
||||||
val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe")
|
|
||||||
theUnsafeField.isAccessible = true
|
|
||||||
|
|
||||||
val theUnsafe = theUnsafeField.get(null)
|
|
||||||
|
|
||||||
clean.invoke(theUnsafe, this)
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ 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.compiler.jarfs.FastJarFileSystem
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarHandler
|
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarHandler
|
||||||
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
|
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
|
||||||
import org.jetbrains.kotlin.config.Services
|
import org.jetbrains.kotlin.config.Services
|
||||||
@@ -1202,8 +1203,8 @@ class CompileServiceImpl(
|
|||||||
|
|
||||||
override fun clearJarCache() {
|
override fun clearJarCache() {
|
||||||
ZipHandler.clearFileAccessorCache()
|
ZipHandler.clearFileAccessorCache()
|
||||||
FastJarHandler.cleanFileAccessorsCache()
|
|
||||||
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
|
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
|
||||||
|
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? FastJarFileSystem)?.clearHandlersCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <R> ifAlive(
|
private inline fun <R> ifAlive(
|
||||||
|
|||||||
+2
-2
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
|||||||
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.compiler.jarfs.FastJarHandler
|
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
|
||||||
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
|
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
|
||||||
import org.jetbrains.kotlin.config.Services
|
import org.jetbrains.kotlin.config.Services
|
||||||
import org.jetbrains.kotlin.daemon.CompileServiceImplBase
|
import org.jetbrains.kotlin.daemon.CompileServiceImplBase
|
||||||
@@ -669,8 +669,8 @@ class CompileServiceServerSideImpl(
|
|||||||
|
|
||||||
override suspend fun clearJarCache() {
|
override suspend fun clearJarCache() {
|
||||||
ZipHandler.clearFileAccessorCache()
|
ZipHandler.clearFileAccessorCache()
|
||||||
FastJarHandler.cleanFileAccessorsCache()
|
|
||||||
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
|
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
|
||||||
|
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? FastJarFileSystem)?.clearHandlersCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun <R> ifAlive(
|
private suspend fun <R> ifAlive(
|
||||||
|
|||||||
Reference in New Issue
Block a user