diff --git a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt index 4c271ad32cf..ed2041ef7b2 100644 --- a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt @@ -20,9 +20,9 @@ import net.rubygrapefruit.platform.ProcessLauncher import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.rmi.* -import java.io.* -import java.rmi.ConnectException -import java.rmi.registry.LocateRegistry +import java.io.File +import java.io.OutputStream +import java.io.PrintStream import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import kotlin.concurrent.thread @@ -61,7 +61,7 @@ public object KotlinCompilerClient { ?.let { File(it) } ?.ifOrNull { exists() } ?: newFlagFile() - return connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, reportingTargets, autostart, checkId) + return connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, reportingTargets, autostart) } public fun connectToCompileService(compilerId: CompilerId, @@ -69,55 +69,31 @@ public object KotlinCompilerClient { daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, reportingTargets: DaemonReportingTargets, - autostart: Boolean = true, - checkId: Boolean = true + autostart: Boolean = true ): CompileService? { var attempts = 0 - var fileLock: FileBasedLock? = null - var shutdonwnPerformed = false try { while (attempts++ < DAEMON_CONNECT_CYCLE_ATTEMPTS) { - val service = tryFindDaemon(File(daemonOptions.runFilesPath), compilerId, reportingTargets) + val (service, newJVMOptions) = tryFindSuitableDaemonOrNewOpts(File(daemonOptions.runFilesPath), compilerId, daemonJVMOptions, { cat, msg -> reportingTargets.report(cat, msg) }) if (service != null) { - if (!checkId || service.checkCompilerId(compilerId)) { - service.registerClient(clientAliveFlagFile.absolutePath) - reportingTargets.report(DaemonReportCategory.DEBUG, "connected to the daemon") - return service - } - reportingTargets.report(DaemonReportCategory.DEBUG, "compiler identity don't match: " + compilerId.mappers.flatMap { it.toArgs("") }.joinToString(" ")) - if (!autostart) return null - reportingTargets.report(DaemonReportCategory.DEBUG, "shutdown the daemon") - service.shutdown() - // TODO: find more reliable way - Thread.sleep(1000) - reportingTargets.report(DaemonReportCategory.DEBUG, "daemon shut down correctly") - shutdonwnPerformed = true + // the newJVMOptions could be checked here for additional parameters, if needed + service.registerClient(clientAliveFlagFile.absolutePath) + reportingTargets.report(DaemonReportCategory.DEBUG, "connected to the daemon") + return service } else { if (!autostart) return null - reportingTargets.report(DaemonReportCategory.DEBUG, if (shutdonwnPerformed) "starting a new daemon" else "no suitable daemon found, starting a new one") + reportingTargets.report(DaemonReportCategory.DEBUG, "no suitable daemon found, starting a new one") } - if (fileLock == null || !fileLock.isLocked()) { - File(daemonOptions.runFilesPath).mkdirs() - fileLock = FileBasedLock(compilerId, daemonOptions) - // need to check the daemons again here, because of possible racing conditions - // note: the algorithm could be simpler if we'll acquire lock right from the beginning, but it may be costly - attempts-- - } - else { - startDaemon(compilerId, daemonJVMOptions, daemonOptions, reportingTargets) - reportingTargets.report(DaemonReportCategory.DEBUG, "daemon started, trying to find it") - } + startDaemon(compilerId, newJVMOptions, daemonOptions, reportingTargets) + reportingTargets.report(DaemonReportCategory.DEBUG, "daemon started, trying to find it") } } catch (e: Exception) { reportingTargets.report(DaemonReportCategory.EXCEPTION, e.toString()) } - finally { - fileLock?.release() - } return null } @@ -270,60 +246,22 @@ public object KotlinCompilerClient { // --- Implementation --------------------------------------- - fun DaemonReportingTargets.report(category: DaemonReportCategory, message: String, source: String = "daemon client") { + private fun DaemonReportingTargets.report(category: DaemonReportCategory, message: String, source: String = "daemon client") { if (category == DaemonReportCategory.DEBUG && !verboseReporting) return - out?.println("[$source] ${category.name()}: $message") + out?.println("[$source] ${category.name}: $message") messages?.add(DaemonReportMessage(category, "[$source] $message")) } - private fun String.extractPortFromRunFilename(digest: String): Int = - makeRunFilenameString(timestamp = "[0-9TZ:\\.\\+-]+", digest = digest, port = "(\\d+)", escapeSequence = "\\").toRegex() - .find(this) - ?.groups?.get(1) - ?.value?.toInt() - ?: 0 - - - private fun tryFindDaemon(registryDir: File, compilerId: CompilerId, reportingTargets: DaemonReportingTargets): CompileService? { - val classPathDigest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString() - val daemons = registryDir.walk() - .map { Pair(it, it.name.extractPortFromRunFilename(classPathDigest)) } - .filter { it.second != 0 } - .mapNotNull { - assert(it.second > 0 && it.second < 0xffff) - reportingTargets.report(DaemonReportCategory.DEBUG, "found suitable daemon on port ${it.second}, trying to connect") - val daemon = tryConnectToDaemon(it.second, reportingTargets) - // cleaning orphaned file; note: daemon should shut itself down if it detects that the run file is deleted - if (daemon == null && !it.first.delete()) { - reportingTargets.report(DaemonReportCategory.INFO, "WARNING: unable to delete seemingly orphaned file '${it.first.absolutePath}', cleanup recommended") - } - daemon - } - .toList() - return when (daemons.size) { - 0 -> null - 1 -> daemons.first() - else -> throw IllegalStateException("Multiple daemons serving the same compiler, reset with the cleanup required") - // TODO: consider implementing automatic recovery instead, e.g. getting the youngest or least used daemon and shut down others - } - } - - - private fun tryConnectToDaemon(port: Int, reportingTargets: DaemonReportingTargets): CompileService? { - try { - val daemon = LocateRegistry.getRegistry(LoopbackNetworkInterface.loopbackInetAddressName, port) - ?.lookup(COMPILER_SERVICE_RMI_NAME) - if (daemon != null) - return daemon as? CompileService ?: - throw ClassCastException("Unable to cast compiler service, actual class received: ${daemon.javaClass}") - reportingTargets.report(DaemonReportCategory.EXCEPTION, "daemon not found") - } - catch (e: ConnectException) { - reportingTargets.report(DaemonReportCategory.EXCEPTION, "cannot connect to registry: " + (e.getCause()?.getMessage() ?: e.getMessage() ?: "unknown exception")) - // ignoring it - processing below - } - return null + private fun tryFindSuitableDaemonOrNewOpts(registryDir: File, compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, report: (DaemonReportCategory, String) -> Unit): Pair { + val aliveWithOpts = walkDaemons(registryDir, compilerId, report) + .map { Pair(it, it.getDaemonJVMOptions()) } + .filter { it.second.isGood } + // TODO: consider to sort the found daemons by memory settings and take the largest (rather that the first found), but carefully analyze possible situations first + val opts = daemonJVMOptions.copy() + return aliveWithOpts.firstOrNull { daemonJVMOptions memorywiseFitsInto it.second.get() } + ?.let { Pair(it.first, opts.updateMemoryUpperBounds(it.second.get())) } + ?: Pair(null, aliveWithOpts.fold(daemonJVMOptions, { opts, d -> opts.updateMemoryUpperBounds(d.second.get()) })) } @@ -396,51 +334,9 @@ public object KotlinCompilerClient { } } } - - - class FileBasedLock(compilerId: CompilerId, daemonOptions: DaemonOptions) { - - private val lockFile: File = - File(daemonOptions.runFilesPath, - makeRunFilenameString(timestamp = "lock", - digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(), - port = "0")) - @Volatile private var locked = acquireLockFile(lockFile) - private val channel = if (locked) RandomAccessFile(lockFile, "rw").channel else null - private val lock = channel?.lock() - - public fun isLocked(): Boolean = locked - - @Synchronized public fun release(): Unit { - if (locked) { - lock?.release() - channel?.close() - lockFile.delete() - locked = false - } - } - - @Synchronized private fun acquireLockFile(lockFile: File): Boolean { - val maxAttempts = COMPILE_DAEMON_STARTUP_LOCK_TIMEOUT_MS / COMPILE_DAEMON_STARTUP_LOCK_TIMEOUT_CHECK_MS + 1 - var attempt = 0L - while (true) { - if (lockFile.createNewFile()) break - // attempt to delete if file is orphaned - if (lockFile.delete() && lockFile.createNewFile()) break - if (lockFile.exists() && ++attempt >= maxAttempts) - throw IOException("Timeout waiting the release of the lock file '${lockFile.absolutePath}") - Thread.sleep(COMPILE_DAEMON_STARTUP_LOCK_TIMEOUT_CHECK_MS) - } - return true - } - } } -public enum class DaemonReportCategory { - DEBUG, INFO, EXCEPTION; -} - public data class DaemonReportMessage(public val category: DaemonReportCategory, public val message: String) public class DaemonReportingTargets(public val out: PrintStream? = null, public val messages: MutableCollection? = null) diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/ClientUtils.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/ClientUtils.kt new file mode 100644 index 00000000000..25df9acc4c9 --- /dev/null +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/ClientUtils.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2015 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.rmi + +import java.io.File +import java.rmi.ConnectException +import java.rmi.registry.LocateRegistry + + +internal val MAX_PORT_NUMBER = 0xffff + + +enum class DaemonReportCategory { + DEBUG, INFO, EXCEPTION; +} + + +fun makeRunFilenameString(timestamp: String, digest: String, port: String, escapeSequence: String = ""): String = "$COMPILE_DAEMON_DEFAULT_FILES_PREFIX$escapeSequence.$timestamp$escapeSequence.$digest$escapeSequence.$port$escapeSequence.run" + + +fun String.extractPortFromRunFilename(digest: String): Int = + makeRunFilenameString(timestamp = "[0-9TZ:\\.\\+-]+", digest = digest, port = "(\\d+)", escapeSequence = "\\").toRegex() + .find(this) + ?.groups?.get(1) + ?.value?.toInt() + ?: 0 + + +fun walkDaemons(registryDir: File, compilerId: CompilerId, report: (DaemonReportCategory, String) -> Unit): Sequence { + val classPathDigest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString() + return registryDir.walk() + .map { Pair(it, it.name.extractPortFromRunFilename(classPathDigest)) } + .filter { it.second != 0 } + .map { + assert(it.second > 0 && it.second < MAX_PORT_NUMBER) + report(DaemonReportCategory.DEBUG, "found daemon on port ${it.second}, trying to connect") + val daemon = tryConnectToDaemon(it.second, report) + // cleaning orphaned file; note: daemon should shut itself down if it detects that the run file is deleted + if (daemon == null && !it.first.delete()) { + report(DaemonReportCategory.INFO, "WARNING: unable to delete seemingly orphaned file '${it.first.absolutePath}', cleanup recommended") + } + daemon + } + .filterNotNull() +} + + +private inline fun tryConnectToDaemon(port: Int, report: (DaemonReportCategory, String) -> Unit): CompileService? { + try { + val daemon = LocateRegistry.getRegistry(LoopbackNetworkInterface.loopbackInetAddressName, port) + ?.lookup(COMPILER_SERVICE_RMI_NAME) + if (daemon != null) + return daemon as? CompileService ?: + throw ClassCastException("Unable to cast compiler service, actual class received: ${daemon.javaClass}") + report(DaemonReportCategory.EXCEPTION, "daemon not found") + } + catch (e: ConnectException) { + report(DaemonReportCategory.EXCEPTION, "cannot connect to registry: " + (e.cause?.message ?: e.message ?: "unknown exception")) + // ignoring it - processing below + } + return null +} diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt index cb1d8b3c1d2..36d144f5855 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt @@ -36,11 +36,14 @@ public interface CompileService : Remote { public val NO_SESSION: Int = 0 } - public sealed class CallResult : Serializable { + public sealed class CallResult : Serializable { class Good(val result: R) : CallResult() class Ok : CallResult() class Dying : CallResult() class Error(val message: String) : CallResult() + + val isGood: Boolean get() = this is Good<*> + fun get(): R = when (this) { is Good -> this.result is Dying -> throw IllegalStateException("Service is dying") diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt index 23b526ba5b9..24c482a9b1e 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt @@ -22,6 +22,7 @@ import java.io.Serializable import java.lang.management.ManagementFactory import java.security.MessageDigest import kotlin.reflect.KMutableProperty1 +import kotlin.text.RegexOption public val COMPILER_JAR_NAME: String = "kotlin-compiler.jar" @@ -55,8 +56,6 @@ public val COMPILE_DAEMON_DEFAULT_RUN_DIR_PATH: String get() = val CLASSPATH_ID_DIGEST = "MD5" -public fun makeRunFilenameString(timestamp: String, digest: String, port: String, escapeSequence: String = ""): String = "$COMPILE_DAEMON_DEFAULT_FILES_PREFIX$escapeSequence.$timestamp$escapeSequence.$digest$escapeSequence.$port$escapeSequence.run" - open class PropMapper>(val dest: C, val prop: P, @@ -307,3 +306,35 @@ public fun configureDaemonOptions(opts: DaemonOptions): DaemonOptions { public fun configureDaemonOptions(): DaemonOptions = configureDaemonOptions(DaemonOptions()) + + +fun String.memToBytes(): Long? = + "(\\d+)([kmg]?)".toRegex() + .matchEntire(this.trim().toLowerCase()) + ?.groups?.let { match -> + match.get(1)?.value?.let { + it.toLong() * + when (match.get(2)?.value) { + "k" -> 1 shl 10 + "m" -> 1 shl 20 + "g" -> 1 shl 30 + else -> 1 + } + } + } + + +private fun daemonJVMOptionsMemoryProps() = + listOf(DaemonJVMOptions::maxMemory, DaemonJVMOptions::maxPermSize, DaemonJVMOptions::reservedCodeCacheSize) + + +infix fun DaemonJVMOptions.memorywiseFitsInto(other: DaemonJVMOptions): Boolean = + daemonJVMOptionsMemoryProps() + .all { (it.get(this).memToBytes() ?: 0) <= (it.get(other).memToBytes() ?: 0) } + + +fun DaemonJVMOptions.updateMemoryUpperBounds(other: DaemonJVMOptions): DaemonJVMOptions { + daemonJVMOptionsMemoryProps() + .forEach { if ((it.get(this).memToBytes() ?: 0) < (it.get(other).memToBytes() ?: 0)) it.set(this, it.get(other)) } + return this +} diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt index 1025e20b6b5..974f2ff86d3 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt @@ -30,6 +30,7 @@ import java.rmi.registry.Registry import java.rmi.server.UnicastRemoteObject import java.util.* import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.logging.Level @@ -81,12 +82,14 @@ class CompileServiceImpl( private val clientProxies: MutableSet = hashSetOf() private val sessions: MutableMap = hashMapOf() - private val sessionsIdCounter: AtomicInteger = AtomicInteger(0) + private val sessionsIdCounter = AtomicInteger(0) private val internalRng = Random() private val classpathWatcher = LazyClasspathWatcher(compilerId.compilerClasspath) - private val compilationsCounter: AtomicInteger = AtomicInteger(0) + private val compilationsCounter = AtomicInteger(0) + private val shutdownQueued = AtomicBoolean(false) + @Volatile private var _lastUsedSeconds = nowSeconds() public val lastUsedSeconds: Long get() = if (rwlock.isWriteLocked || rwlock.readLockCount - rwlock.readHoldCount > 0) nowSeconds() else _lastUsedSeconds @@ -138,7 +141,7 @@ class CompileServiceImpl( } } } - // assuming wrap, jumping to random number to reduce probability of further ckashes + // assuming wrap, jumping to random number to reduce probability of further clashes newId = sessionsIdCounter.addAndGet(internalRng.nextInt()) } throw Exception("Invalid state or algorithm error") @@ -163,7 +166,7 @@ class CompileServiceImpl( override fun getUsedMemory(): CompileService.CallResult = ifAlive { usedMemory(withGC = true) } override fun shutdown() { - ifAliveExclusive { + ifAliveExclusive(ignoreCompilerChanged = true) { log.info("Shutdown started") alive = false UnicastRemoteObject.unexportObject(this, true) @@ -261,7 +264,8 @@ class CompileServiceImpl( // 3. clean dead clients, then check if any left - conditional shutdown (with small delay) synchronized(clientProxies) { clientProxies.removeAll( clientProxies.filter{ !it.isAlive }) } - if (clientProxies.none()) { + if (clientProxies.none() && compilationsCounter.get() > 0 && !shutdownQueued.get()) { + log.info("No more clients left, delayed shutdown in ${daemonOptions.shutdownDelayMilliseconds}ms") shutdownWithDelay() } // 4. check idle timeout - shutdown @@ -279,11 +283,17 @@ class CompileServiceImpl( } private fun shutdownWithDelay() { + shutdownQueued.set(true) val currentCompilationsCount = compilationsCounter.get() timer.schedule(daemonOptions.shutdownDelayMilliseconds) { + shutdownQueued.set(false) if (currentCompilationsCount == compilationsCounter.get()) { + log.fine("Execute delayed shutdown") shutdown() } + else { + log.info("Cancel delayed shutdown due to new client") + } } } @@ -336,7 +346,7 @@ class CompileServiceImpl( } - fun checkedCompile(args: Array, serviceOut: PrintStream, rpcProfiler: Profiler, body: () -> R): R { + private fun checkedCompile(args: Array, serviceOut: PrintStream, rpcProfiler: Profiler, body: () -> R): R { try { if (args.none()) throw IllegalArgumentException("Error: empty arguments list.") @@ -378,20 +388,39 @@ class CompileServiceImpl( } } - fun ifAlive(body: () -> R): CompileService.CallResult = rwlock.read { - if (!alive) CompileService.CallResult.Dying() - CompileService.CallResult.Good( body() ) + private fun ifAlive(ignoreCompilerChanged: Boolean = false, body: () -> R): CompileService.CallResult = rwlock.read { + ifAliveChecksImpl(ignoreCompilerChanged) { CompileService.CallResult.Good(body()) } } // TODO: find how to implement it without using unique name for this variant; making name deliberately ugly meanwhile - fun ifAlive_Nothing(body: () -> Unit): CompileService.CallResult = rwlock.read { - if (!alive) CompileService.CallResult.Dying() - body() - CompileService.CallResult.Ok() + private fun ifAlive_Nothing(ignoreCompilerChanged: Boolean = false, body: () -> Unit): CompileService.CallResult = rwlock.read { + ifAliveChecksImpl(ignoreCompilerChanged) { + body() + CompileService.CallResult.Ok() + } } - fun ifAliveExclusive(body: () -> R): CompileService.CallResult = rwlock.write { - if (!alive) CompileService.CallResult.Dying() - CompileService.CallResult.Good( body() ) + private fun ifAliveExclusive(ignoreCompilerChanged: Boolean = false, body: () -> R): CompileService.CallResult = rwlock.write { + ifAliveChecksImpl(ignoreCompilerChanged) { CompileService.CallResult.Good(body()) } } + + inline private fun ifAliveChecksImpl(ignoreCompilerChanged: Boolean = false, body: () -> CompileService.CallResult): CompileService.CallResult = + when { + !alive -> CompileService.CallResult.Dying() + !ignoreCompilerChanged && classpathWatcher.isChanged -> { + log.info("Compiler changed, scheduling shutdown") + timer.schedule(1) { shutdown() } + CompileService.CallResult.Dying() + } + else -> { + try { + body() + } + catch (e: Exception) { + log.log(Level.SEVERE, "Exception", e) + CompileService.CallResult.Error(e.message ?: "unknown") + } + } + } + } diff --git a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt index e18630fdf96..1ac5555483c 100644 --- a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt @@ -44,7 +44,7 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() { val compilerId by lazy(LazyThreadSafetyMode.NONE) { CompilerId.makeCompilerId(compilerClassPath) } private fun compileOnDaemon(clientAliveFile: File, compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, vararg args: String): CompilerResults { - val daemon = KotlinCompilerClient.connectToCompileService(compilerId, clientAliveFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true, checkId = true) + val daemon = KotlinCompilerClient.connectToCompileService(compilerId, clientAliveFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true) TestCase.assertNotNull("failed to connect daemon", daemon) daemon?.registerClient(clientAliveFile.absolutePath) val strm = ByteArrayOutputStream() @@ -264,7 +264,7 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() { try { val daemonOptions = DaemonOptions(runFilesPath = File(tmpdir, getTestName(true)).absolutePath) val daemonJVMOptions = configureDaemonJVMOptions(inheritMemoryLimits = false, inheritAdditionalProperties = false) - val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true, checkId = true) + val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true) TestCase.assertNotNull("failed to connect daemon", daemon) val (registry, port) = findPortAndCreateRegistry(10, 16384, 65535)