[IC] Make CompilationTransaction to be able to close CachesManager
This commit is contained in:
committed by
Space Team
parent
3ed651a7a6
commit
25a3dcf3d1
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
|
class CachesManagerCloseException(cause: Throwable) : Exception("Failed to close caches", cause)
|
||||||
@@ -35,6 +35,16 @@ interface CompilationTransaction : Closeable {
|
|||||||
* Marks the transaction as successful, so it should not revert changes if it is able to perform revert.
|
* Marks the transaction as successful, so it should not revert changes if it is able to perform revert.
|
||||||
*/
|
*/
|
||||||
fun markAsSuccessful()
|
fun markAsSuccessful()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A closeable object (caches manager) that is had to be closed on the transaction close
|
||||||
|
*/
|
||||||
|
var cachesManager: Closeable?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A throwable that was thrown during the transaction execution
|
||||||
|
*/
|
||||||
|
var executionThrowable: Throwable?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CompilationTransaction.write(file: Path, writeAction: () -> Unit) {
|
fun CompilationTransaction.write(file: Path, writeAction: () -> Unit) {
|
||||||
@@ -55,6 +65,22 @@ fun CompilationTransaction.writeBytes(file: Path, array: ByteArray) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <R> CompilationTransaction.runWithin(
|
||||||
|
exceptionTransformer: (Throwable) -> R = { throw it },
|
||||||
|
body: (CompilationTransaction) -> R
|
||||||
|
): R {
|
||||||
|
return runCatching {
|
||||||
|
use {
|
||||||
|
try {
|
||||||
|
body(this)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
executionThrowable = t
|
||||||
|
throw t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.recover { exceptionTransformer(it) }.getOrThrow() // some exceptions may be transformed into results
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dummy implementation of compilation transaction
|
* A dummy implementation of compilation transaction
|
||||||
*/
|
*/
|
||||||
@@ -73,10 +99,21 @@ class DummyCompilationTransaction : CompilationTransaction {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override var cachesManager: Closeable? = null
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
|
override var executionThrowable: Throwable? = null
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
try {
|
||||||
|
cachesManager?.close()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
if (executionThrowable != null) {
|
||||||
|
executionThrowable?.addSuppressed(CachesManagerCloseException(t))
|
||||||
|
} else {
|
||||||
|
throw CachesManagerCloseException(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,12 +210,30 @@ class RecoverableCompilationTransaction(
|
|||||||
successful = true
|
successful = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var cachesManager: Closeable? = null
|
||||||
|
|
||||||
|
override var executionThrowable: Throwable? = null
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
if (successful) {
|
val mainException = runCatching {
|
||||||
cleanupStash()
|
cachesManager?.close()
|
||||||
} else {
|
}.exceptionOrNull()?.run {
|
||||||
revertChanges()
|
successful = false
|
||||||
cleanupStash()
|
val exception = CachesManagerCloseException(this)
|
||||||
|
executionThrowable?.addSuppressed(exception)
|
||||||
|
executionThrowable ?: exception
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (successful) {
|
||||||
|
cleanupStash()
|
||||||
|
} else {
|
||||||
|
revertChanges()
|
||||||
|
cleanupStash()
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
mainException?.addSuppressed(t)
|
||||||
|
throw mainException ?: t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-35
@@ -160,6 +160,11 @@ abstract class IncrementalCompilerRunner<
|
|||||||
class Failed(val reason: BuildAttribute, val cause: Throwable) : ICResult
|
class Failed(val reason: BuildAttribute, val cause: Throwable) : ICResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun incrementalCompilationExceptionTransformer(t: Throwable): ICResult = when (t) {
|
||||||
|
is CachesManagerCloseException -> ICResult.Failed(IC_FAILED_TO_CLOSE_CACHES, t)
|
||||||
|
else -> throw t
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to compile incrementally and returns either [ICResult.Completed], [ICResult.RequiresRebuild], or [ICResult.Failed].
|
* Attempts to compile incrementally and returns either [ICResult.Completed], [ICResult.RequiresRebuild], or [ICResult.Failed].
|
||||||
*
|
*
|
||||||
@@ -178,9 +183,12 @@ abstract class IncrementalCompilerRunner<
|
|||||||
}
|
}
|
||||||
changedFiles as ChangedFiles.Known?
|
changedFiles as ChangedFiles.Known?
|
||||||
|
|
||||||
createTransaction().use { transaction ->
|
return createTransaction().runWithin(::incrementalCompilationExceptionTransformer) { transaction ->
|
||||||
val icContext = createIncrementalCompilationContext(projectDir, transaction)
|
val icContext = createIncrementalCompilationContext(projectDir, transaction)
|
||||||
val caches = createCacheManager(icContext, args)
|
val caches = createCacheManager(icContext, args).also {
|
||||||
|
// this way we make the transaction to be responsible for closing the caches manager
|
||||||
|
transaction.cachesManager = it
|
||||||
|
}
|
||||||
|
|
||||||
fun compile(): ICResult {
|
fun compile(): ICResult {
|
||||||
// Step 1: Get changed files
|
// Step 1: Get changed files
|
||||||
@@ -235,41 +243,11 @@ abstract class IncrementalCompilerRunner<
|
|||||||
return ICResult.Completed(exitCode)
|
return ICResult.Completed(exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeCaches(caches: CacheManager, activeException: Throwable) {
|
compile().also { icResult ->
|
||||||
try {
|
if (icResult is ICResult.Completed && icResult.exitCode == ExitCode.OK) {
|
||||||
caches.close()
|
transaction.markAsSuccessful()
|
||||||
} catch (e: Throwable) {
|
|
||||||
activeException.addSuppressed(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because `caches` is a Closeable resource, it is important to close them in both cases:
|
|
||||||
// 1. in the event of an exception
|
|
||||||
// 2. after a normal execution
|
|
||||||
// Note: Historically, closing caches used to throw exceptions sometimes, so currently we want to collect those exceptions. In the
|
|
||||||
// future, if closing caches is safe, we can simplify the code by using Kotlin's `Closable.use` function (similar to the code in
|
|
||||||
// `compileNonIncrementally`).
|
|
||||||
val icResult = try {
|
|
||||||
compile()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
// Case 1 - Close the caches upon an exception
|
|
||||||
closeCaches(caches, e)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 2 - Close the caches after a normal execution
|
|
||||||
try {
|
|
||||||
caches.close()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
return ICResult.Failed(
|
|
||||||
IC_FAILED_TO_CLOSE_CACHES,
|
|
||||||
RuntimeException("Failed to close caches, previous ICResult `$icResult` was discarded", e)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (icResult is ICResult.Completed && icResult.exitCode == ExitCode.OK) {
|
|
||||||
transaction.markAsSuccessful()
|
|
||||||
}
|
|
||||||
return icResult
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user