Extract common caches
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||
import org.jetbrains.kotlin.incremental.storage.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.supertypes
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Incremental cache common for JVM and JS
|
||||
*/
|
||||
open class IncrementalCacheCommon(workingDir: File) : BasicMapsOwner(workingDir) {
|
||||
companion object {
|
||||
private val SUBTYPES = "subtypes"
|
||||
private val SUPERTYPES = "supertypes"
|
||||
private val CLASS_FQ_NAME_TO_SOURCE = "class-fq-name-to-source"
|
||||
}
|
||||
|
||||
private val dependents = arrayListOf<IncrementalCacheCommon>()
|
||||
fun addDependentCache(cache: IncrementalCacheCommon) {
|
||||
dependents.add(cache)
|
||||
}
|
||||
val thisWithDependentCaches: Iterable<IncrementalCacheCommon> by lazy {
|
||||
val result = arrayListOf(this)
|
||||
result.addAll(dependents)
|
||||
result
|
||||
}
|
||||
|
||||
private val subtypesMap = registerMap(SubtypesMap(SUBTYPES.storageFile))
|
||||
private val supertypesMap = registerMap(SupertypesMap(SUPERTYPES.storageFile))
|
||||
protected val classFqNameToSourceMap = registerMap(ClassFqNameToSourceMap(CLASS_FQ_NAME_TO_SOURCE.storageFile))
|
||||
|
||||
fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
||||
subtypesMap[className].asSequence()
|
||||
|
||||
fun getSourceFileIfClass(fqName: FqName): File? =
|
||||
classFqNameToSourceMap[fqName]
|
||||
|
||||
protected fun addToClassStorage(proto: ProtoBuf.Class, nameResolver: NameResolver, srcFile: File) {
|
||||
val supertypes = proto.supertypes(TypeTable(proto.typeTable))
|
||||
val parents = supertypes.map { nameResolver.getClassId(it.className).asSingleFqName() }
|
||||
.filter { it.asString() != "kotlin.Any" }
|
||||
.toSet()
|
||||
val child = nameResolver.getClassId(proto.fqName).asSingleFqName()
|
||||
|
||||
parents.forEach { subtypesMap.add(it, child) }
|
||||
|
||||
val removedSupertypes = supertypesMap[child].filter { it !in parents }
|
||||
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
|
||||
|
||||
supertypesMap[child] = parents
|
||||
classFqNameToSourceMap[child] = srcFile
|
||||
}
|
||||
|
||||
protected fun removeAllFromClassStorage(removedClasses: Collection<FqName>) {
|
||||
if (removedClasses.isEmpty()) return
|
||||
|
||||
val removedFqNames = removedClasses.toSet()
|
||||
|
||||
for (cache in thisWithDependentCaches) {
|
||||
val parentsFqNames = hashSetOf<FqName>()
|
||||
val childrenFqNames = hashSetOf<FqName>()
|
||||
|
||||
for (removedFqName in removedFqNames) {
|
||||
parentsFqNames.addAll(cache.supertypesMap[removedFqName])
|
||||
childrenFqNames.addAll(cache.subtypesMap[removedFqName])
|
||||
|
||||
cache.supertypesMap.remove(removedFqName)
|
||||
cache.subtypesMap.remove(removedFqName)
|
||||
}
|
||||
|
||||
for (child in childrenFqNames) {
|
||||
cache.supertypesMap.removeValues(child, removedFqNames)
|
||||
}
|
||||
|
||||
for (parent in parentsFqNames) {
|
||||
cache.subtypesMap.removeValues(parent, removedFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
removedFqNames.forEach { classFqNameToSourceMap.remove(it) }
|
||||
}
|
||||
|
||||
protected class ClassFqNameToSourceMap(storageFile: File) : BasicStringMap<String>(storageFile, EnumeratorStringDescriptor(), PathStringDescriptor) {
|
||||
operator fun set(fqName: FqName, sourceFile: File) {
|
||||
storage[fqName.asString()] = sourceFile.canonicalPath
|
||||
}
|
||||
|
||||
operator fun get(fqName: FqName): File? =
|
||||
storage[fqName.asString()]?.let(::File)
|
||||
|
||||
fun remove(fqName: FqName) {
|
||||
storage.remove(fqName.asString())
|
||||
}
|
||||
|
||||
override fun dumpValue(value: String) = value
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,6 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.supertypes
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
@@ -53,7 +51,7 @@ open class IncrementalCacheImpl<Target>(
|
||||
private val targetDataRoot: File,
|
||||
targetOutputDir: File?,
|
||||
target: Target
|
||||
) : BasicMapsOwner(), IncrementalCache {
|
||||
) : IncrementalCacheCommon(File(targetDataRoot, KOTLIN_CACHE_DIRECTORY_NAME)), IncrementalCache {
|
||||
companion object {
|
||||
private val PROTO_MAP = "proto"
|
||||
private val CONSTANTS_MAP = "constants"
|
||||
@@ -63,19 +61,11 @@ open class IncrementalCacheImpl<Target>(
|
||||
private val SOURCE_TO_CLASSES = "source-to-classes"
|
||||
private val DIRTY_OUTPUT_CLASSES = "dirty-output-classes"
|
||||
private val INLINE_FUNCTIONS = "inline-functions"
|
||||
private val SUBTYPES = "subtypes"
|
||||
private val SUPERTYPES = "supertypes"
|
||||
private val CLASS_FQ_NAME_TO_SOURCE = "class-fq-name-to-source"
|
||||
private val INTERNAL_NAME_TO_SOURCE = "internal-name-to-source"
|
||||
|
||||
private val MODULE_MAPPING_FILE_NAME = "." + ModuleMapping.MAPPING_FILE_EXT
|
||||
}
|
||||
|
||||
private val baseDir = File(targetDataRoot, KOTLIN_CACHE_DIRECTORY_NAME)
|
||||
|
||||
protected val String.storageFile: File
|
||||
get() = File(baseDir, this + "." + CACHE_EXTENSION)
|
||||
|
||||
private val protoMap = registerMap(ProtoMap(PROTO_MAP.storageFile))
|
||||
private val constantsMap = registerMap(ConstantsMap(CONSTANTS_MAP.storageFile))
|
||||
private val packagePartMap = registerMap(PackagePartMap(PACKAGE_PARTS.storageFile))
|
||||
@@ -84,27 +74,13 @@ open class IncrementalCacheImpl<Target>(
|
||||
private val sourceToClassesMap = registerMap(SourceToClassesMap(SOURCE_TO_CLASSES.storageFile))
|
||||
private val dirtyOutputClassesMap = registerMap(DirtyOutputClassesMap(DIRTY_OUTPUT_CLASSES.storageFile))
|
||||
private val inlineFunctionsMap = registerMap(InlineFunctionsMap(INLINE_FUNCTIONS.storageFile))
|
||||
private val subtypesMap = registerMap(SubtypesMap(SUBTYPES.storageFile))
|
||||
private val supertypesMap = registerMap(SupertypesMap(SUPERTYPES.storageFile))
|
||||
private val classFqNameToSourceMap = registerMap(ClassFqNameToSourceMap(CLASS_FQ_NAME_TO_SOURCE.storageFile))
|
||||
// todo: try to use internal names only?
|
||||
private val internalNameToSource = registerMap(InternalNameToSourcesMap(INTERNAL_NAME_TO_SOURCE.storageFile))
|
||||
|
||||
private val dependents = arrayListOf<IncrementalCacheImpl<Target>>()
|
||||
private val outputDir by lazy(LazyThreadSafetyMode.NONE) { requireNotNull(targetOutputDir) { "Target is expected to have output directory: $target" } }
|
||||
|
||||
val thisWithDependentCaches: Iterable<IncrementalCacheImpl<Target>> by lazy {
|
||||
val result = arrayListOf(this)
|
||||
result.addAll(dependents)
|
||||
result
|
||||
}
|
||||
|
||||
protected open fun debugLog(message: String) {}
|
||||
|
||||
fun addDependentCache(cache: IncrementalCacheImpl<Target>) {
|
||||
dependents.add(cache)
|
||||
}
|
||||
|
||||
fun markOutputClassesDirty(removedAndCompiledSources: List<File>) {
|
||||
for (sourceFile in removedAndCompiledSources) {
|
||||
val classes = sourceToClassesMap[sourceFile]
|
||||
@@ -121,12 +97,6 @@ open class IncrementalCacheImpl<Target>(
|
||||
fun classesBySources(sources: Iterable<File>): Iterable<JvmClassName> =
|
||||
sources.flatMap { sourceToClassesMap[it] }
|
||||
|
||||
fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
||||
subtypesMap[className].asSequence()
|
||||
|
||||
fun getSourceFileIfClass(fqName: FqName): File? =
|
||||
classFqNameToSourceMap[fqName]
|
||||
|
||||
fun sourcesByInternalName(internalName: String): Collection<File> =
|
||||
internalNameToSource[internalName]
|
||||
|
||||
@@ -310,7 +280,7 @@ open class IncrementalCacheImpl<Target>(
|
||||
internalNameToSource.remove(it.internalName)
|
||||
}
|
||||
|
||||
removeAllFromClassStorage(dirtyClasses)
|
||||
removeAllFromClassStorage(dirtyClasses.map { it.fqNameForClassNameWithoutDollars })
|
||||
|
||||
dirtyOutputClassesMap.clean()
|
||||
return changesInfo
|
||||
@@ -555,22 +525,6 @@ open class IncrementalCacheImpl<Target>(
|
||||
}
|
||||
}
|
||||
|
||||
inner class ClassFqNameToSourceMap(storageFile: File) : BasicStringMap<String>(storageFile, EnumeratorStringDescriptor(), PathStringDescriptor) {
|
||||
operator fun set(fqName: FqName, sourceFile: File) {
|
||||
storage[fqName.asString()] = sourceFile.canonicalPath
|
||||
}
|
||||
|
||||
operator fun get(fqName: FqName): File? =
|
||||
storage[fqName.asString()]?.let(::File)
|
||||
|
||||
fun remove(fqName: FqName) {
|
||||
storage.remove(fqName.asString())
|
||||
}
|
||||
|
||||
override fun dumpValue(value: String) = value
|
||||
}
|
||||
|
||||
|
||||
inner class InternalNameToSourcesMap(storageFile: File) : BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer) {
|
||||
operator fun set(internalName: String, sourceFiles: Iterable<File>) {
|
||||
storage[internalName] = sourceFiles.map { it.canonicalPath }
|
||||
@@ -588,49 +542,8 @@ open class IncrementalCacheImpl<Target>(
|
||||
}
|
||||
|
||||
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass, srcFile: File) {
|
||||
val classData = JvmProtoBufUtil.readClassDataFrom(kotlinClass.classHeader.data!!, kotlinClass.classHeader.strings!!)
|
||||
val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable))
|
||||
val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() }
|
||||
.filter { it.asString() != "kotlin.Any" }
|
||||
.toSet()
|
||||
val child = kotlinClass.classId.asSingleFqName()
|
||||
|
||||
parents.forEach { subtypesMap.add(it, child) }
|
||||
|
||||
val removedSupertypes = supertypesMap[child].filter { it !in parents }
|
||||
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
|
||||
|
||||
supertypesMap[child] = parents
|
||||
classFqNameToSourceMap[kotlinClass.className.fqNameForClassNameWithoutDollars] = srcFile
|
||||
}
|
||||
|
||||
private fun removeAllFromClassStorage(removedClasses: Collection<JvmClassName>) {
|
||||
if (removedClasses.isEmpty()) return
|
||||
|
||||
val removedFqNames = removedClasses.map { it.fqNameForClassNameWithoutDollars }.toSet()
|
||||
|
||||
for (cache in thisWithDependentCaches) {
|
||||
val parentsFqNames = hashSetOf<FqName>()
|
||||
val childrenFqNames = hashSetOf<FqName>()
|
||||
|
||||
for (removedFqName in removedFqNames) {
|
||||
parentsFqNames.addAll(cache.supertypesMap[removedFqName])
|
||||
childrenFqNames.addAll(cache.subtypesMap[removedFqName])
|
||||
|
||||
cache.supertypesMap.remove(removedFqName)
|
||||
cache.subtypesMap.remove(removedFqName)
|
||||
}
|
||||
|
||||
for (child in childrenFqNames) {
|
||||
cache.supertypesMap.removeValues(child, removedFqNames)
|
||||
}
|
||||
|
||||
for (parent in parentsFqNames) {
|
||||
cache.subtypesMap.removeValues(parent, removedFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
removedFqNames.forEach { classFqNameToSourceMap.remove(it) }
|
||||
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(kotlinClass.classHeader.data!!, kotlinClass.classHeader.strings!!)
|
||||
addToClassStorage(proto, nameResolver, srcFile)
|
||||
}
|
||||
|
||||
private inner class DirtyOutputClassesMap(storageFile: File) : BasicStringMap<Boolean>(storageFile, BooleanDataDescriptor.INSTANCE) {
|
||||
|
||||
@@ -29,15 +29,12 @@ import java.io.File
|
||||
import java.util.*
|
||||
|
||||
|
||||
open class LookupStorage(private val targetDataDir: File) : BasicMapsOwner() {
|
||||
open class LookupStorage(targetDataDir: File) : BasicMapsOwner(targetDataDir) {
|
||||
companion object {
|
||||
private val DELETED_TO_SIZE_TRESHOLD = 0.5
|
||||
private val MINIMUM_GARBAGE_COLLECTIBLE_SIZE = 10000
|
||||
}
|
||||
|
||||
private val String.storageFile: File
|
||||
get() = File(targetDataDir, this + "." + CACHE_EXTENSION)
|
||||
|
||||
private val countersFile = "counters".storageFile
|
||||
private val idToFile = registerMap(IdToFileMap("id-to-file".storageFile))
|
||||
private val fileToId = registerMap(FileToIdMap("file-to-id".storageFile))
|
||||
|
||||
@@ -187,8 +187,8 @@ data class DirtyData(
|
||||
val dirtyClassesFqNames: Collection<FqName> = emptyList()
|
||||
)
|
||||
|
||||
fun <Target> CompilationResult.getDirtyData(
|
||||
caches: Iterable<IncrementalCacheImpl<Target>>,
|
||||
fun CompilationResult.getDirtyData(
|
||||
caches: Iterable<IncrementalCacheCommon>,
|
||||
reporter: ICReporter
|
||||
): DirtyData {
|
||||
val dirtyLookupSymbols = HashSet<LookupSymbol>()
|
||||
@@ -241,8 +241,8 @@ fun mapLookupSymbolsToFiles(
|
||||
return dirtyFiles
|
||||
}
|
||||
|
||||
fun <Target> mapClassesFqNamesToFiles(
|
||||
caches: Iterable<IncrementalCacheImpl<Target>>,
|
||||
fun mapClassesFqNamesToFiles(
|
||||
caches: Iterable<IncrementalCacheCommon>,
|
||||
classesFqNames: Iterable<FqName>,
|
||||
reporter: ICReporter,
|
||||
excludes: Set<File> = emptySet()
|
||||
@@ -265,9 +265,9 @@ fun <Target> mapClassesFqNamesToFiles(
|
||||
private fun findSrcDirRoot(file: File, roots: Iterable<File>): File? =
|
||||
roots.firstOrNull { FileUtil.isAncestor(it, file, false) }
|
||||
|
||||
fun <Target> withSubtypes(
|
||||
fun withSubtypes(
|
||||
typeFqName: FqName,
|
||||
caches: Iterable<IncrementalCacheImpl<Target>>
|
||||
caches: Iterable<IncrementalCacheCommon>
|
||||
): Set<FqName> {
|
||||
val types = LinkedList(listOf(typeFqName))
|
||||
val subtypes = hashSetOf<FqName>()
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
package org.jetbrains.kotlin.incremental.storage
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.File
|
||||
|
||||
open class BasicMapsOwner {
|
||||
open class BasicMapsOwner(private val baseDir: File) {
|
||||
private val maps = arrayListOf<BasicMap<*, *>>()
|
||||
|
||||
companion object {
|
||||
val CACHE_EXTENSION = "tab"
|
||||
}
|
||||
|
||||
protected val String.storageFile: File
|
||||
get() = File(baseDir, this + "." + CACHE_EXTENSION)
|
||||
|
||||
protected fun <K, V, M : BasicMap<K, V>> registerMap(map: M): M {
|
||||
maps.add(map)
|
||||
return map
|
||||
|
||||
@@ -87,7 +87,7 @@ class LazyStorage<K, V>(
|
||||
try {
|
||||
storage?.close()
|
||||
}
|
||||
catch (ignored: IOException) {
|
||||
catch (ignored: Throwable) {
|
||||
}
|
||||
|
||||
PersistentHashMap.deleteFilesStartingWith(storageFile)
|
||||
|
||||
+45
-40
@@ -16,59 +16,64 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import java.io.File
|
||||
|
||||
class IncrementalCachesManager (
|
||||
private val targetId: TargetId,
|
||||
private val cacheDirectory: File,
|
||||
private val outputDir: File,
|
||||
private val reporter: ICReporter
|
||||
abstract class IncrementalCachesManager (
|
||||
protected val cachesRootDir: File,
|
||||
protected val reporter: ICReporter
|
||||
) {
|
||||
private val incrementalCacheDir = File(cacheDirectory, "increCache.${targetId.name}")
|
||||
private val lookupCacheDir = File(cacheDirectory, "lookups")
|
||||
private var incrementalCacheField: GradleIncrementalCacheImpl? = null
|
||||
private var lookupCacheField: LookupStorage? = null
|
||||
private val caches = arrayListOf<BasicMapsOwner>()
|
||||
protected fun <T : BasicMapsOwner> T.registerCache() {
|
||||
caches.add(this)
|
||||
}
|
||||
|
||||
val incrementalCache: GradleIncrementalCacheImpl
|
||||
get() {
|
||||
if (incrementalCacheField == null) {
|
||||
val targetDataRoot = incrementalCacheDir.apply { mkdirs() }
|
||||
incrementalCacheField = GradleIncrementalCacheImpl(targetDataRoot, outputDir, targetId, reporter)
|
||||
}
|
||||
private val inputSnapshotsCacheDir = File(cachesRootDir, "inputs").apply { mkdirs() }
|
||||
private val lookupCacheDir = File(cachesRootDir, "lookups").apply { mkdirs() }
|
||||
|
||||
return incrementalCacheField!!
|
||||
}
|
||||
|
||||
val lookupCache: LookupStorage
|
||||
get() {
|
||||
if (lookupCacheField == null) {
|
||||
lookupCacheField = LookupStorage(lookupCacheDir.apply { mkdirs() })
|
||||
}
|
||||
|
||||
return lookupCacheField!!
|
||||
}
|
||||
val inputsCache: InputsCache = InputsCache(inputSnapshotsCacheDir, reporter).apply { registerCache() }
|
||||
val lookupCache: LookupStorage = LookupStorage(lookupCacheDir).apply { registerCache() }
|
||||
|
||||
fun clean() {
|
||||
close(flush = false)
|
||||
cacheDirectory.deleteRecursively()
|
||||
caches.forEach { it.clean() }
|
||||
cachesRootDir.deleteRecursively()
|
||||
}
|
||||
|
||||
fun close(flush: Boolean = false) {
|
||||
incrementalCacheField?.let {
|
||||
fun close(flush: Boolean = false): Boolean {
|
||||
var successful = true
|
||||
|
||||
for (cache in caches) {
|
||||
if (flush) {
|
||||
it.flush(false)
|
||||
try {
|
||||
cache.flush(false)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
successful = false
|
||||
reporter.report { "Exception when flushing cache ${cache.javaClass}: $e" }
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
cache.close()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
successful = false
|
||||
reporter.report { "Exception when closing cache ${cache.javaClass}: $e" }
|
||||
}
|
||||
it.close()
|
||||
incrementalCacheField = null
|
||||
}
|
||||
|
||||
lookupCacheField?.let {
|
||||
if (flush) {
|
||||
it.flush(false)
|
||||
}
|
||||
it.close()
|
||||
lookupCacheField = null
|
||||
}
|
||||
return successful
|
||||
}
|
||||
}
|
||||
|
||||
class IncrementalJvmCachesManager(
|
||||
targetId: TargetId,
|
||||
cacheDirectory: File,
|
||||
outputDir: File,
|
||||
reporter: ICReporter
|
||||
) : IncrementalCachesManager(cacheDirectory, reporter) {
|
||||
|
||||
private val jvmCacheFile = File(cacheDirectory, "jvm").apply { mkdirs() }
|
||||
val jvmCache = IncrementalCacheImpl(jvmCacheFile, outputDir, targetId).apply { registerCache() }
|
||||
}
|
||||
+42
-41
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import com.intellij.util.io.PersistentEnumeratorBase
|
||||
import org.jetbrains.kotlin.annotation.AnnotationFileUpdater
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
@@ -40,7 +39,6 @@ import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
fun makeIncrementally(
|
||||
@@ -64,7 +62,7 @@ fun makeIncrementally(
|
||||
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
|
||||
versions, reporter)
|
||||
compiler.compile(kotlinFiles, args, messageCollector) {
|
||||
it.incrementalCache.sourceSnapshotMap.compareAndUpdate(sourceFiles)
|
||||
it.inputsCache.sourceSnapshotMap.compareAndUpdate(sourceFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,16 +105,15 @@ class IncrementalJvmCompilerRunner(
|
||||
getChangedFiles: (IncrementalCachesManager)->ChangedFiles
|
||||
): ExitCode {
|
||||
val targetId = TargetId(name = args.moduleName!!, type = "java-production")
|
||||
var caches = IncrementalCachesManager(targetId, cacheDirectory, File(args.destination), reporter)
|
||||
var caches = IncrementalJvmCachesManager(targetId, cacheDirectory, File(args.destination), reporter)
|
||||
|
||||
fun onError(e: Exception): ExitCode {
|
||||
fun rebuild(): ExitCode {
|
||||
caches.clean()
|
||||
dirtySourcesSinceLastTimeFile.delete()
|
||||
args.destinationAsFile.deleteRecursively()
|
||||
|
||||
// todo: warn?
|
||||
reporter.report { "Possible cache corruption. Rebuilding. $e" }
|
||||
// try to rebuild
|
||||
val javaFilesProcessor = ChangedJavaFilesProcessor(reporter)
|
||||
caches = IncrementalCachesManager(targetId, cacheDirectory, args.destinationAsFile, reporter)
|
||||
caches = IncrementalJvmCachesManager(targetId, cacheDirectory, args.destinationAsFile, reporter)
|
||||
return compileIncrementally(args, caches, javaFilesProcessor, allKotlinSources, targetId, CompilationMode.Rebuild, messageCollector)
|
||||
}
|
||||
|
||||
@@ -124,17 +121,24 @@ class IncrementalJvmCompilerRunner(
|
||||
val javaFilesProcessor = ChangedJavaFilesProcessor(reporter)
|
||||
val changedFiles = getChangedFiles(caches)
|
||||
val compilationMode = calculateSourcesToCompile(javaFilesProcessor, caches, changedFiles, args)
|
||||
compileIncrementally(args, caches, javaFilesProcessor, allKotlinSources, targetId, compilationMode, messageCollector)
|
||||
|
||||
val exitCode = when (compilationMode) {
|
||||
is CompilationMode.Incremental -> {
|
||||
compileIncrementally(args, caches, javaFilesProcessor, allKotlinSources, targetId, compilationMode, messageCollector)
|
||||
}
|
||||
is CompilationMode.Rebuild -> {
|
||||
rebuild()
|
||||
}
|
||||
}
|
||||
|
||||
if (!caches.close(flush = true)) throw RuntimeException("Could not flush caches")
|
||||
|
||||
return exitCode
|
||||
}
|
||||
catch (e: PersistentEnumeratorBase.CorruptedException) {
|
||||
onError(e)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
onError(e)
|
||||
}
|
||||
finally {
|
||||
caches.close(flush = true)
|
||||
reporter.report { "flushed incremental caches" }
|
||||
catch (e: Exception) {
|
||||
// todo: warn?
|
||||
reporter.report { "Possible cache corruption. Rebuilding. $e" }
|
||||
rebuild()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,15 +151,12 @@ class IncrementalJvmCompilerRunner(
|
||||
|
||||
private fun calculateSourcesToCompile(
|
||||
javaFilesProcessor: ChangedJavaFilesProcessor,
|
||||
caches: IncrementalCachesManager,
|
||||
caches: IncrementalJvmCachesManager,
|
||||
changedFiles: ChangedFiles,
|
||||
args: K2JVMCompilerArguments
|
||||
): CompilationMode {
|
||||
fun rebuild(reason: ()->String): CompilationMode {
|
||||
reporter.report {"Non-incremental compilation will be performed: ${reason()}"}
|
||||
caches.clean()
|
||||
dirtySourcesSinceLastTimeFile.delete()
|
||||
args.destinationAsFile.deleteRecursively()
|
||||
return CompilationMode.Rebuild
|
||||
}
|
||||
|
||||
@@ -196,9 +197,9 @@ class IncrementalJvmCompilerRunner(
|
||||
dirtyFiles.addAll(dirtyFilesFromLookups)
|
||||
}
|
||||
|
||||
val dirtyClassesFqNames = classpathChanges.fqNames.flatMap {withSubtypes(it, listOf(caches.incrementalCache))}
|
||||
val dirtyClassesFqNames = classpathChanges.fqNames.flatMap { withSubtypes(it, listOf(caches.jvmCache)) }
|
||||
if (dirtyClassesFqNames.any()) {
|
||||
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.incrementalCache), dirtyClassesFqNames, reporter)
|
||||
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.jvmCache), dirtyClassesFqNames, reporter)
|
||||
dirtyFiles.addAll(dirtyFilesFromFqNames)
|
||||
}
|
||||
|
||||
@@ -250,7 +251,7 @@ class IncrementalJvmCompilerRunner(
|
||||
|
||||
private fun compileIncrementally(
|
||||
args: K2JVMCompilerArguments,
|
||||
caches: IncrementalCachesManager,
|
||||
caches: IncrementalJvmCachesManager,
|
||||
javaFilesProcessor: ChangedJavaFilesProcessor,
|
||||
allKotlinSources: List<File>,
|
||||
targetId: TargetId,
|
||||
@@ -283,9 +284,9 @@ class IncrementalJvmCompilerRunner(
|
||||
var exitCode = ExitCode.OK
|
||||
while (dirtySources.any()) {
|
||||
val lookupTracker = LookupTrackerImpl(LookupTracker.DO_NOTHING)
|
||||
val outdatedClasses = caches.incrementalCache.classesBySources(dirtySources)
|
||||
caches.incrementalCache.markOutputClassesDirty(dirtySources)
|
||||
caches.incrementalCache.removeOutputForSourceFiles(dirtySources)
|
||||
val outdatedClasses = caches.jvmCache.classesBySources(dirtySources)
|
||||
caches.jvmCache.markOutputClassesDirty(dirtySources)
|
||||
caches.inputsCache.removeOutputForSourceFiles(dirtySources)
|
||||
|
||||
val (sourcesToCompile, removedKotlinSources) = dirtySources.partition(File::exists)
|
||||
|
||||
@@ -295,7 +296,7 @@ class IncrementalJvmCompilerRunner(
|
||||
val text = allSourcesToCompile.joinToString(separator = System.getProperty("line.separator")) { it.canonicalPath }
|
||||
dirtySourcesSinceLastTimeFile.writeText(text)
|
||||
|
||||
val compilerOutput = compileChanged(listOf(targetId), sourcesToCompile.toSet(), args, { caches.incrementalCache }, lookupTracker, messageCollector)
|
||||
val compilerOutput = compileChanged(listOf(targetId), sourcesToCompile.toSet(), args, caches.jvmCache, lookupTracker, messageCollector)
|
||||
exitCode = compilerOutput.exitCode
|
||||
val generatedFiles = compilerOutput.generatedFiles
|
||||
anyClassesCompiled = anyClassesCompiled || generatedFiles.isNotEmpty() || removedKotlinSources.isNotEmpty()
|
||||
@@ -310,7 +311,7 @@ class IncrementalJvmCompilerRunner(
|
||||
|
||||
if (compilationMode is CompilationMode.Incremental) {
|
||||
val dirtySourcesSet = dirtySources.toHashSet()
|
||||
val additionalDirtyFiles = additionalDirtyFiles(caches, generatedFiles).filter { it !in dirtySourcesSet }
|
||||
val additionalDirtyFiles = additionalDirtyFiles(caches.jvmCache, generatedFiles).filter { it !in dirtySourcesSet }
|
||||
if (additionalDirtyFiles.isNotEmpty()) {
|
||||
dirtySources.addAll(additionalDirtyFiles)
|
||||
continue
|
||||
@@ -318,10 +319,10 @@ class IncrementalJvmCompilerRunner(
|
||||
}
|
||||
|
||||
allGeneratedFiles.addAll(generatedFiles)
|
||||
caches.incrementalCache.registerOutputForSourceFiles(generatedFiles)
|
||||
caches.inputsCache.registerOutputForSourceFiles(generatedFiles)
|
||||
val compilationResult = updateIncrementalCaches(listOf(targetId), generatedFiles,
|
||||
compiledWithErrors = exitCode != ExitCode.OK,
|
||||
getIncrementalCache = { caches.incrementalCache })
|
||||
getIncrementalCache = { caches.jvmCache })
|
||||
|
||||
caches.lookupCache.update(lookupTracker, sourcesToCompile, removedKotlinSources)
|
||||
|
||||
@@ -329,13 +330,13 @@ class IncrementalJvmCompilerRunner(
|
||||
break
|
||||
}
|
||||
|
||||
val (dirtyLookupSymbols, dirtyClassFqNames) = compilationResult.getDirtyData(listOf(caches.incrementalCache), reporter)
|
||||
val (dirtyLookupSymbols, dirtyClassFqNames) = compilationResult.getDirtyData(listOf(caches.jvmCache), reporter)
|
||||
val compiledInThisIterationSet = sourcesToCompile.toHashSet()
|
||||
|
||||
with (dirtySources) {
|
||||
clear()
|
||||
addAll(mapLookupSymbolsToFiles(caches.lookupCache, dirtyLookupSymbols, reporter, excludes = compiledInThisIterationSet))
|
||||
addAll(mapClassesFqNamesToFiles(listOf(caches.incrementalCache), dirtyClassFqNames, reporter, excludes = compiledInThisIterationSet))
|
||||
addAll(mapClassesFqNamesToFiles(listOf(caches.jvmCache), dirtyClassFqNames, reporter, excludes = compiledInThisIterationSet))
|
||||
}
|
||||
|
||||
buildDirtyLookupSymbols.addAll(dirtyLookupSymbols)
|
||||
@@ -364,14 +365,14 @@ class IncrementalJvmCompilerRunner(
|
||||
}
|
||||
|
||||
private fun additionalDirtyFiles(
|
||||
caches: IncrementalCachesManager,
|
||||
cache: IncrementalCacheImpl<TargetId>,
|
||||
generatedFiles: List<GeneratedFile<TargetId>>
|
||||
): Collection<File> {
|
||||
val result = HashSet<File>()
|
||||
|
||||
fun partsByFacadeName(facadeInternalName: String): List<File> {
|
||||
val parts = caches.incrementalCache.getStableMultifileFacadeParts(facadeInternalName) ?: emptyList()
|
||||
return parts.flatMap { caches.incrementalCache.sourcesByInternalName(it) }
|
||||
val parts = cache.getStableMultifileFacadeParts(facadeInternalName) ?: emptyList()
|
||||
return parts.flatMap { cache.sourcesByInternalName(it) }
|
||||
}
|
||||
|
||||
for (generatedFile in generatedFiles) {
|
||||
@@ -382,7 +383,7 @@ class IncrementalJvmCompilerRunner(
|
||||
when (outputClass.classHeader.kind) {
|
||||
KotlinClassHeader.Kind.CLASS -> {
|
||||
val fqName = outputClass.className.fqNameForClassNameWithoutDollars
|
||||
val cachedSourceFile = caches.incrementalCache.getSourceFileIfClass(fqName)
|
||||
val cachedSourceFile = cache.getSourceFileIfClass(fqName)
|
||||
|
||||
if (cachedSourceFile != null) {
|
||||
result.add(cachedSourceFile)
|
||||
@@ -405,7 +406,7 @@ class IncrementalJvmCompilerRunner(
|
||||
targets: List<TargetId>,
|
||||
sourcesToCompile: Set<File>,
|
||||
args: K2JVMCompilerArguments,
|
||||
getIncrementalCache: (TargetId)->GradleIncrementalCacheImpl,
|
||||
cache: IncrementalCacheImpl<TargetId>,
|
||||
lookupTracker: LookupTracker,
|
||||
messageCollector: MessageCollector
|
||||
): CompileChangedResults {
|
||||
@@ -428,7 +429,7 @@ class IncrementalJvmCompilerRunner(
|
||||
val messageCollector = MessageCollectorWrapper(messageCollector, outputItemCollector)
|
||||
|
||||
try {
|
||||
val incrementalCaches = makeIncrementalCachesMap(targets, { listOf<TargetId>() }, getIncrementalCache, { this })
|
||||
val incrementalCaches = makeIncrementalCachesMap(targets, { listOf<TargetId>() }, { cache }, { this })
|
||||
val compilationCanceledStatus = object : CompilationCanceledStatus {
|
||||
override fun checkCanceled() {
|
||||
}
|
||||
|
||||
+4
-5
@@ -19,18 +19,17 @@ package org.jetbrains.kotlin.incremental
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.incremental.snapshots.FileSnapshotMap
|
||||
import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner
|
||||
import org.jetbrains.kotlin.incremental.storage.BasicStringMap
|
||||
import org.jetbrains.kotlin.incremental.storage.PathStringDescriptor
|
||||
import org.jetbrains.kotlin.incremental.storage.StringCollectionExternalizer
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import java.io.File
|
||||
|
||||
class GradleIncrementalCacheImpl(
|
||||
targetDataRoot: File,
|
||||
targetOutputDir: File?,
|
||||
target: TargetId,
|
||||
class InputsCache(
|
||||
workingDir: File,
|
||||
private val reporter: ICReporter
|
||||
) : IncrementalCacheImpl<TargetId>(targetDataRoot, targetOutputDir, target) {
|
||||
) : BasicMapsOwner(workingDir) {
|
||||
companion object {
|
||||
private val SOURCE_TO_OUTPUT_FILES = "source-to-output"
|
||||
private val SOURCE_SNAPSHOTS = "source-snapshot"
|
||||
+4
-8
@@ -29,15 +29,14 @@ import java.io.File
|
||||
/**
|
||||
* "Global" cache holder. Should be created once per root project.
|
||||
*/
|
||||
internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner(), ArtifactDifferenceRegistryProvider {
|
||||
internal class BuildCacheStorage(private val workingDir: File) : BasicMapsOwner(workingDir), ArtifactDifferenceRegistryProvider {
|
||||
companion object {
|
||||
private val OWN_VERSION = 0
|
||||
private val ARTIFACT_DIFFERENCE = "artifact-difference"
|
||||
}
|
||||
|
||||
private val log = Logging.getLogger(this.javaClass)
|
||||
private val cachesDir: File = File(workingDir, "caches").apply { mkdirs() }
|
||||
private val versionFile = File(cachesDir, "version.txt")
|
||||
private val versionFile = File(workingDir, "version.txt")
|
||||
private val version = CacheVersion(
|
||||
OWN_VERSION,
|
||||
versionFile,
|
||||
@@ -50,9 +49,6 @@ internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner(), ArtifactD
|
||||
@Volatile
|
||||
private var artifactDifferenceRegistry: ArtifactDifferenceRegistryImpl? = null
|
||||
|
||||
private val String.storageFile: File
|
||||
get() = File(cachesDir, this + "." + CACHE_EXTENSION)
|
||||
|
||||
@Synchronized
|
||||
override fun <T> withRegistry(report: (String)->Unit, fn: (ArtifactDifferenceRegistry)->T): T? {
|
||||
try {
|
||||
@@ -95,8 +91,8 @@ internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner(), ArtifactD
|
||||
log.kotlinDebug { "Exception while closing caches: ${e.stackTraceStr}" }
|
||||
}
|
||||
|
||||
cachesDir.deleteRecursively()
|
||||
cachesDir.mkdirs()
|
||||
workingDir.deleteRecursively()
|
||||
workingDir.mkdirs()
|
||||
versionFile.delete()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user