Fixes after review
This commit is contained in:
+45
-41
@@ -24,6 +24,7 @@ import java.io.PrintStream
|
|||||||
import java.rmi.ConnectException
|
import java.rmi.ConnectException
|
||||||
import java.rmi.Remote
|
import java.rmi.Remote
|
||||||
import java.rmi.registry.LocateRegistry
|
import java.rmi.registry.LocateRegistry
|
||||||
|
import java.util.concurrent.Semaphore
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
import kotlin.concurrent.read
|
import kotlin.concurrent.read
|
||||||
@@ -45,7 +46,6 @@ public class KotlinCompilerClient {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val DAEMON_STARTUP_TIMEOUT_MS = 10000L
|
val DAEMON_STARTUP_TIMEOUT_MS = 10000L
|
||||||
val DAEMON_STARTUP_CHECK_INTERVAL_MS = 100L
|
|
||||||
|
|
||||||
private fun connectToService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? {
|
private fun connectToService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? {
|
||||||
|
|
||||||
@@ -71,9 +71,13 @@ public class KotlinCompilerClient {
|
|||||||
|
|
||||||
|
|
||||||
private fun startDaemon(compilerId: CompilerId, daemonLaunchingOptions: DaemonLaunchingOptions, daemonOptions: DaemonOptions, errStream: PrintStream) {
|
private fun startDaemon(compilerId: CompilerId, daemonLaunchingOptions: DaemonLaunchingOptions, daemonOptions: DaemonOptions, errStream: PrintStream) {
|
||||||
val javaExecutable = listOf(System.getProperty("java.home"), "bin", "java").joinToString(File.separator)
|
val javaExecutable = File(System.getProperty("java.home"), "bin").let {
|
||||||
|
val javaw = File(it, "javaw.exe")
|
||||||
|
if (javaw.exists()) javaw
|
||||||
|
else File(it, "java")
|
||||||
|
}
|
||||||
// TODO: add some specific environment variables to the cp and may be command line, to allow some specific startup configs
|
// TODO: add some specific environment variables to the cp and may be command line, to allow some specific startup configs
|
||||||
val args = listOf(javaExecutable,
|
val args = listOf(javaExecutable.absolutePath,
|
||||||
"-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) +
|
"-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) +
|
||||||
daemonLaunchingOptions.jvmParams +
|
daemonLaunchingOptions.jvmParams +
|
||||||
COMPILER_DAEMON_CLASS_FQN +
|
COMPILER_DAEMON_CLASS_FQN +
|
||||||
@@ -84,16 +88,18 @@ public class KotlinCompilerClient {
|
|||||||
// assuming daemon process is deaf and (mostly) silent, so do not handle streams
|
// assuming daemon process is deaf and (mostly) silent, so do not handle streams
|
||||||
val daemon = processBuilder.start()
|
val daemon = processBuilder.start()
|
||||||
|
|
||||||
val lock = ReentrantReadWriteLock()
|
var isEchoRead = Semaphore(1)
|
||||||
var isEchoRead = false
|
isEchoRead.acquire()
|
||||||
|
|
||||||
val stdouThread =
|
val stdoutThread =
|
||||||
thread {
|
thread {
|
||||||
daemon.getInputStream()
|
daemon.getInputStream()
|
||||||
.reader()
|
.reader()
|
||||||
.forEachLine {
|
.forEachLine {
|
||||||
if (daemonOptions.startEcho.isNotEmpty() && it.contains(daemonOptions.startEcho))
|
if (daemonOptions.startEcho.isNotEmpty() && it.contains(daemonOptions.startEcho)) {
|
||||||
lock.write { isEchoRead = true; return@forEachLine }
|
isEchoRead.release()
|
||||||
|
return@forEachLine
|
||||||
|
}
|
||||||
errStream.println("[daemon] " + it)
|
errStream.println("[daemon] " + it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,14 +107,10 @@ public class KotlinCompilerClient {
|
|||||||
// trying to wait for process
|
// trying to wait for process
|
||||||
if (daemonOptions.startEcho.isNotEmpty()) {
|
if (daemonOptions.startEcho.isNotEmpty()) {
|
||||||
errStream.println("[daemon client] waiting for daemon to respond")
|
errStream.println("[daemon client] waiting for daemon to respond")
|
||||||
var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MS / DAEMON_STARTUP_CHECK_INTERVAL_MS
|
val succeeded = isEchoRead.tryAcquire(DAEMON_STARTUP_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
while (waitMillis-- > 0) {
|
|
||||||
Thread.sleep(DAEMON_STARTUP_CHECK_INTERVAL_MS)
|
|
||||||
if (!daemon.isAlive() || lock.read { isEchoRead } == true) break;
|
|
||||||
}
|
|
||||||
if (!daemon.isAlive())
|
if (!daemon.isAlive())
|
||||||
throw Exception("Daemon terminated unexpectedly")
|
throw Exception("Daemon terminated unexpectedly")
|
||||||
if (lock.read { isEchoRead } == false)
|
if (!succeeded)
|
||||||
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms")
|
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms")
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -117,9 +119,9 @@ public class KotlinCompilerClient {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself
|
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself
|
||||||
if (stdouThread.isAlive)
|
if (stdoutThread.isAlive)
|
||||||
// TODO: find better method to stop the thread, but seems it will require asynchronous consuming of the stream
|
// TODO: find better method to stop the thread, but seems it will require asynchronous consuming of the stream
|
||||||
lock.write { stdouThread.stop() }
|
stdoutThread.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +184,7 @@ public class KotlinCompilerClient {
|
|||||||
val outStrm = RemoteOutputStreamServer(out)
|
val outStrm = RemoteOutputStreamServer(out)
|
||||||
val cacheServers = hashMapOf<String, RemoteIncrementalCacheServer>()
|
val cacheServers = hashMapOf<String, RemoteIncrementalCacheServer>()
|
||||||
try {
|
try {
|
||||||
caches.forEach { cacheServers.put( it.getKey(), RemoteIncrementalCacheServer( it.getValue())) }
|
caches.mapValuesTo(cacheServers, { RemoteIncrementalCacheServer( it.getValue()) })
|
||||||
return compiler.remoteIncrementalCompile(args, cacheServers, outStrm, CompileService.OutputFormat.XML)
|
return compiler.remoteIncrementalCompile(args, cacheServers, outStrm, CompileService.OutputFormat.XML)
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -242,34 +244,36 @@ public class KotlinCompilerClient {
|
|||||||
compilerId.updateDigest()
|
compilerId.updateDigest()
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop)?.let {
|
val daemon = connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop)
|
||||||
when {
|
|
||||||
clientOptions.stop -> {
|
if (daemon == null) {
|
||||||
println("Shutdown the daemon")
|
if (clientOptions.stop) println("No daemon found to shut down")
|
||||||
it.shutdown()
|
else throw Exception("Unable to connect to daemon")
|
||||||
println("Daemon shut down successfully")
|
}
|
||||||
|
else when {
|
||||||
|
clientOptions.stop -> {
|
||||||
|
println("Shutdown the daemon")
|
||||||
|
daemon.shutdown()
|
||||||
|
println("Daemon shut down successfully")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
||||||
|
val outStrm = RemoteOutputStreamServer(System.out)
|
||||||
|
try {
|
||||||
|
val memBefore = daemon.getUsedMemory() / 1024
|
||||||
|
val startTime = System.nanoTime()
|
||||||
|
val res = daemon.remoteCompile(filteredArgs.toArrayList().toTypedArray(), outStrm, CompileService.OutputFormat.PLAIN)
|
||||||
|
val endTime = System.nanoTime()
|
||||||
|
println("Compilation result code: $res")
|
||||||
|
val memAfter = daemon.getUsedMemory() / 1024
|
||||||
|
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
||||||
|
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
||||||
}
|
}
|
||||||
else -> {
|
finally {
|
||||||
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
outStrm.disconnect()
|
||||||
val outStrm = RemoteOutputStreamServer(System.out)
|
|
||||||
try {
|
|
||||||
val memBefore = it.getUsedMemory() / 1024
|
|
||||||
val startTime = System.nanoTime()
|
|
||||||
val res = it.remoteCompile(filteredArgs.toArrayList().toTypedArray(), outStrm, CompileService.OutputFormat.PLAIN)
|
|
||||||
val endTime = System.nanoTime()
|
|
||||||
println("Compilation result code: $res")
|
|
||||||
val memAfter = it.getUsedMemory() / 1024
|
|
||||||
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
|
||||||
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
outStrm.disconnect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?: if (clientOptions.stop) println("No daemon found to shut down")
|
|
||||||
else throw Exception("Unable to connect to daemon")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -35,8 +35,8 @@ class RemoteOutputStreamServer(val out: OutputStream) : RemoteOutputStream {
|
|||||||
out.close()
|
out.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(data: ByteArray, start: Int, length: Int) {
|
override fun write(data: ByteArray, offset: Int, length: Int) {
|
||||||
out.write(data, start, length)
|
out.write(data, offset, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(dataByte: Int) {
|
override fun write(dataByte: Int) {
|
||||||
@@ -117,10 +117,11 @@ val COMPILER_ID_DIGEST = "MD5"
|
|||||||
|
|
||||||
|
|
||||||
fun updateSingleFileDigest(file: File, md: MessageDigest) {
|
fun updateSingleFileDigest(file: File, md: MessageDigest) {
|
||||||
val stream = DigestInputStream(file.inputStream(), md)
|
DigestInputStream(file.inputStream(), md).use {
|
||||||
val buf = ByteArray(1024)
|
val buf = ByteArray(1024)
|
||||||
while (stream.read(buf) == buf.size()) {}
|
while (it.read(buf) != -1) { }
|
||||||
stream.close()
|
it.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateForAllClasses(dir: File, md: MessageDigest) {
|
fun updateForAllClasses(dir: File, md: MessageDigest) {
|
||||||
|
|||||||
@@ -57,10 +57,7 @@ class LogStream(name: String) : OutputStream() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun flush(data: ByteArray, offset: Int, length: Int) {
|
fun flush(data: ByteArray, offset: Int, length: Int) {
|
||||||
if (offset == 0 && length == data.size())
|
log.info(lineBuf.toString() + data.toString().substring(offset, length))
|
||||||
log.info(lineBuf.toString() + data.toString())
|
|
||||||
else
|
|
||||||
log.info(lineBuf.toString() + data.toString().substring(offset, length))
|
|
||||||
lineBuf.setLength(0)
|
lineBuf.setLength(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.io.File
|
|||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
|
import java.lang.management.ManagementFactory
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.rmi.registry.Registry
|
import java.rmi.registry.Registry
|
||||||
import java.rmi.server.UnicastRemoteObject
|
import java.rmi.server.UnicastRemoteObject
|
||||||
@@ -103,6 +104,13 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
|||||||
return (rt.totalMemory() - rt.freeMemory())
|
return (rt.totalMemory() - rt.freeMemory())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun usedMemoryMX(): Long {
|
||||||
|
System.gc()
|
||||||
|
val memoryMXBean= ManagementFactory.getMemoryMXBean()
|
||||||
|
val memHeap=memoryMXBean.getHeapMemoryUsage()
|
||||||
|
return memHeap.used
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadKotlinVersionFromResource(): String {
|
private fun loadKotlinVersionFromResource(): String {
|
||||||
(javaClass.classLoader as? URLClassLoader)
|
(javaClass.classLoader as? URLClassLoader)
|
||||||
?.findResource("META-INF/MANIFEST.MF")
|
?.findResource("META-INF/MANIFEST.MF")
|
||||||
@@ -121,14 +129,17 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
|||||||
if (args.none())
|
if (args.none())
|
||||||
throw IllegalArgumentException("Error: empty arguments list.")
|
throw IllegalArgumentException("Error: empty arguments list.")
|
||||||
log.info("Starting compilation with args: " + args.joinToString(" "))
|
log.info("Starting compilation with args: " + args.joinToString(" "))
|
||||||
|
val startMemMX = usedMemoryMX() / 1024
|
||||||
val startMem = usedMemory() / 1024
|
val startMem = usedMemory() / 1024
|
||||||
val startTime = System.nanoTime()
|
val startTime = System.nanoTime()
|
||||||
val res = body()
|
val res = body()
|
||||||
val endTime = System.nanoTime()
|
val endTime = System.nanoTime()
|
||||||
val endMem = usedMemory() / 1024
|
val endMem = usedMemory() / 1024
|
||||||
|
val endMemMX = usedMemoryMX() / 1024
|
||||||
log.info("Done with result " + res.toString())
|
log.info("Done with result " + res.toString())
|
||||||
log.info("Elapsed time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
log.info("Elapsed time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
||||||
log.info("Used memory: $endMem kb (${"%+d".format(endMem - startMem)} kb)")
|
log.info("Used memory: $endMem kb (${"%+d".format(endMem - startMem)} kb)")
|
||||||
|
log.info("Used memory (from MemoryMXBean): $endMemMX kb (${"%+d".format(endMemMX - startMemMX)} kb)")
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
|
|||||||
@@ -53,29 +53,17 @@ public class DaemonPolicy(val port: Int) : Policy() {
|
|||||||
|
|
||||||
|
|
||||||
class DaemonPermissionCollection : PermissionCollection() {
|
class DaemonPermissionCollection : PermissionCollection() {
|
||||||
var perms = ArrayList<Permission>()
|
val perms = ArrayList<Permission>()
|
||||||
|
|
||||||
override fun add(p: Permission) {
|
override fun add(p: Permission) {
|
||||||
perms.add(p)
|
perms.add(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun implies(p: Permission): Boolean {
|
override fun implies(p: Permission): Boolean = perms.any { implies(p) }
|
||||||
val i = perms.iterator()
|
|
||||||
while (i.hasNext()) {
|
|
||||||
if (i.next().implies(p)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun elements(): Enumeration<Permission> {
|
override fun elements(): Enumeration<Permission> = Collections.enumeration(perms)
|
||||||
return Collections.enumeration(perms)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isReadOnly(): Boolean {
|
override fun isReadOnly(): Boolean = false
|
||||||
return false
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// companion object {
|
// companion object {
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ public class KotlinCompilerRunner {
|
|||||||
CompilerSettings compilerSettings,
|
CompilerSettings compilerSettings,
|
||||||
MessageCollector messageCollector,
|
MessageCollector messageCollector,
|
||||||
CompilerEnvironment environment,
|
CompilerEnvironment environment,
|
||||||
Map<String, IncrementalCache> incrementalCaches, File moduleFile,
|
Map<String, IncrementalCache> incrementalCaches,
|
||||||
|
File moduleFile,
|
||||||
OutputItemsCollector collector
|
OutputItemsCollector collector
|
||||||
) {
|
) {
|
||||||
K2JVMCompilerArguments arguments = mergeBeans(commonArguments, k2jvmArguments);
|
K2JVMCompilerArguments arguments = mergeBeans(commonArguments, k2jvmArguments);
|
||||||
@@ -78,7 +79,8 @@ public class KotlinCompilerRunner {
|
|||||||
@NotNull CompilerSettings compilerSettings,
|
@NotNull CompilerSettings compilerSettings,
|
||||||
@NotNull MessageCollector messageCollector,
|
@NotNull MessageCollector messageCollector,
|
||||||
@NotNull CompilerEnvironment environment,
|
@NotNull CompilerEnvironment environment,
|
||||||
Map<String, IncrementalCache> incrementalCaches, @NotNull OutputItemsCollector collector,
|
Map<String, IncrementalCache> incrementalCaches,
|
||||||
|
@NotNull OutputItemsCollector collector,
|
||||||
@NotNull Collection<File> sourceFiles,
|
@NotNull Collection<File> sourceFiles,
|
||||||
@NotNull List<String> libraryFiles,
|
@NotNull List<String> libraryFiles,
|
||||||
@NotNull File outputFile
|
@NotNull File outputFile
|
||||||
@@ -156,7 +158,6 @@ public class KotlinCompilerRunner {
|
|||||||
// exec() returns an ExitCode object, class of which is loaded with a different class loader,
|
// exec() returns an ExitCode object, class of which is loaded with a different class loader,
|
||||||
// so we take it's contents through reflection
|
// so we take it's contents through reflection
|
||||||
return getReturnCodeFromObject(rc);
|
return getReturnCodeFromObject(rc);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
MessageCollectorUtil.reportException(messageCollector, e);
|
MessageCollectorUtil.reportException(messageCollector, e);
|
||||||
|
|||||||
Reference in New Issue
Block a user