Fix synchronization when working with IC caches
IC caches could be modified and read from different threads. In JPS builder these threads are RMI worker (invoked from Compiler Daemon) and JPS worker thread. Proper synchronization fixes cases when caches could become broken. #KT-42265 Fixed #KT-42194 Fixed #KT-42265 Fixed #KT-42937 Fixed
This commit is contained in:
+10
-1
@@ -30,7 +30,12 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
|
||||
) {
|
||||
val pathConverter = IncrementalFileToPathConverter(rootProjectDir)
|
||||
private val caches = arrayListOf<BasicMapsOwner>()
|
||||
|
||||
var isClosed = false
|
||||
|
||||
@Synchronized
|
||||
protected fun <T : BasicMapsOwner> T.registerCache() {
|
||||
assert(!isClosed) { "Attempted to add new cache into closed storage." }
|
||||
caches.add(this)
|
||||
}
|
||||
|
||||
@@ -41,9 +46,12 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
|
||||
val lookupCache: LookupStorage = LookupStorage(lookupCacheDir, pathConverter).apply { registerCache() }
|
||||
abstract val platformCache: PlatformCache
|
||||
|
||||
@Synchronized
|
||||
fun close(flush: Boolean = false): Boolean {
|
||||
if (isClosed) {
|
||||
return true
|
||||
}
|
||||
var successful = true
|
||||
|
||||
for (cache in caches) {
|
||||
if (flush) {
|
||||
try {
|
||||
@@ -62,6 +70,7 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
|
||||
}
|
||||
}
|
||||
|
||||
isClosed = true
|
||||
return successful
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
abstract class IncrementalCompilerRunner<
|
||||
@@ -97,7 +98,10 @@ abstract class IncrementalCompilerRunner<
|
||||
val allKotlinFiles = allSourceFiles.filter { it.isKotlinFile(kotlinSourceFilesExtensions) }
|
||||
return compileIncrementally(args, caches, allKotlinFiles, CompilationMode.Rebuild(reason), messageCollector)
|
||||
}
|
||||
|
||||
// attempt IC
|
||||
// if OK or failed compilation - return
|
||||
// internal error - clear
|
||||
// failed to close - clear
|
||||
return try {
|
||||
val changedFiles = providedChangedFiles ?: caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
|
||||
val compilationMode = sourcesToCompile(caches, changedFiles, args, messageCollector)
|
||||
@@ -143,8 +147,8 @@ abstract class IncrementalCompilerRunner<
|
||||
}
|
||||
}
|
||||
|
||||
assert(!destinationDir.exists()) { "Could not delete destination dir $destinationDir" }
|
||||
assert(!workingDir.exists()) { "Could not delete caches dir $workingDir" }
|
||||
if (destinationDir.exists()) throw IOException("Could not delete directory $destinationDir.")
|
||||
if (workingDir.exists()) throw IOException("Could not delete internal caches in folder $workingDir")
|
||||
destinationDir.mkdirs()
|
||||
workingDir.mkdirs()
|
||||
}
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ class FileSnapshotMap(storageFile: File) : BasicStringMap<FileSnapshot>(storageF
|
||||
override fun dumpValue(value: FileSnapshot): String =
|
||||
value.toString()
|
||||
|
||||
@Synchronized
|
||||
fun compareAndUpdate(newFiles: Iterable<File>): ChangedFiles.Known {
|
||||
val snapshotProvider = SimpleFileSnapshotProviderImpl()
|
||||
val newOrModified = ArrayList<File>()
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ class SourceToOutputFilesMap(
|
||||
storageFile: File
|
||||
) : BasicStringMap<Collection<String>>(storageFile, PathStringDescriptor, StringCollectionExternalizer) {
|
||||
|
||||
@Synchronized
|
||||
operator fun set(sourceFile: File, outputFiles: Collection<File>) {
|
||||
storage[sourceFile.absolutePath] = outputFiles.map { it.absolutePath }
|
||||
}
|
||||
@@ -22,6 +23,7 @@ class SourceToOutputFilesMap(
|
||||
override fun dumpValue(value: Collection<String>) =
|
||||
value.dumpCollection()
|
||||
|
||||
@Synchronized
|
||||
fun remove(file: File): Collection<File> =
|
||||
get(file).also { storage.remove(file.absolutePath) }
|
||||
}
|
||||
Reference in New Issue
Block a user