diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/BasicMap.kt b/build-common/src/org/jetbrains/kotlin/incremental/storage/BasicMap.kt index 1940bd2b9be..3c6ff37abcc 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/storage/BasicMap.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/BasicMap.kt @@ -32,7 +32,7 @@ abstract class BasicMap, V>( ) { protected val storage: LazyStorage = CachingLazyStorage(storageFile, keyDescriptor, valueExternalizer).let { if (icContext.keepIncrementalCompilationCachesInMemory) { - InMemoryStorageWrapper(it).also { wrapper -> + DefaultInMemoryStorageWrapper(it).also { wrapper -> icContext.transaction.registerInMemoryStorageWrapper(wrapper) } } else { diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/InMemoryStorageWrapper.kt b/build-common/src/org/jetbrains/kotlin/incremental/storage/InMemoryStorageWrapper.kt index d6696f6bc3a..8d1b6931320 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/storage/InMemoryStorageWrapper.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/InMemoryStorageWrapper.kt @@ -8,12 +8,16 @@ package org.jetbrains.kotlin.incremental.storage import java.util.* import kotlin.collections.LinkedHashMap +interface InMemoryStorageWrapper : LazyStorage { + fun resetInMemoryChanges() +} + /** * An in-memory wrapper for [origin] that keeps all the write operations in-memory. * Flushes all the changes to the [origin] on [flush] invocation. * [resetInMemoryChanges] should be called to reset in-memory changes of this wrapper. */ -class InMemoryStorageWrapper(private val origin: LazyStorage) : LazyStorage { +class DefaultInMemoryStorageWrapper(private val origin: LazyStorage) : InMemoryStorageWrapper { private val inMemoryStorage = LinkedHashMap>() private val removedKeys = hashSetOf() private var isCleanRequested = false @@ -21,7 +25,7 @@ class InMemoryStorageWrapper(private val origin: LazyStorage) : Lazy override val keys: Collection get() = if (isCleanRequested) inMemoryStorage.keys else (origin.keys - removedKeys) + inMemoryStorage.keys - fun resetInMemoryChanges() { + override fun resetInMemoryChanges() { isCleanRequested = false inMemoryStorage.clear() removedKeys.clear() diff --git a/build-common/test/org/jetbrains/kotlin/incremental/CompilationTransactionTest.kt b/build-common/test/org/jetbrains/kotlin/incremental/CompilationTransactionTest.kt index cd14695a93d..8c47ad082e3 100644 --- a/build-common/test/org/jetbrains/kotlin/incremental/CompilationTransactionTest.kt +++ b/build-common/test/org/jetbrains/kotlin/incremental/CompilationTransactionTest.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.incremental import org.jetbrains.kotlin.build.report.DoNothingBuildReporter +import org.jetbrains.kotlin.incremental.storage.InMemoryStorageWrapper import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertTrue @@ -26,6 +27,32 @@ private class CacheMock(private val throwsException: Boolean = false) : Closeabl } } +private class InMemoryStorageWrapperMock : InMemoryStorageWrapper { + var reset = false + + override fun resetInMemoryChanges() { + reset = true + } + + override val keys: Collection = emptyList() + + override fun clean() {} + + override fun flush(memoryCachesOnly: Boolean) {} + + override fun close() {} + + override fun append(key: Any, value: Any) {} + + override fun remove(key: Any) {} + + override fun set(key: Any, value: Any) {} + + override fun get(key: Any) = null + + override fun contains(key: Any) = false +} + abstract class BaseCompilationTransactionTest { @TempDir protected lateinit var stashDir: Path @@ -84,6 +111,38 @@ abstract class BaseCompilationTransactionTest { } } } + + @Test + fun testInMemoryWrappersAreResetOnUnsuccessfulTransaction() { + val inMemoryStorageWrapperMock = InMemoryStorageWrapperMock() + useTransaction { + registerInMemoryStorageWrapper(inMemoryStorageWrapperMock) + } + assertTrue(inMemoryStorageWrapperMock.reset) + } + + @Test + fun testInMemoryWrappersAreResetOnExecutionException() { + val inMemoryStorageWrapperMock = InMemoryStorageWrapperMock() + assertThrows { + useTransaction { + registerInMemoryStorageWrapper(inMemoryStorageWrapperMock) + markAsSuccessful() + throw Exception() + } + } + assertTrue(inMemoryStorageWrapperMock.reset) + } + + @Test + fun testInMemoryWrappersAreNotResetOnSuccessfulTransaction() { + val inMemoryStorageWrapperMock = InMemoryStorageWrapperMock() + useTransaction { + registerInMemoryStorageWrapper(inMemoryStorageWrapperMock) + markAsSuccessful() + } + assertFalse(inMemoryStorageWrapperMock.reset) + } } class NonRecoverableCompilationTransactionTest : BaseCompilationTransactionTest() {