Passing port through daemon client API to allow port reusing for client-side components, introducing operations tracer interface for testing purposes

This commit is contained in:
Ilya Chernikov
2015-10-22 15:13:45 +02:00
parent 3f46a13a56
commit 2dfca72f38
7 changed files with 92 additions and 43 deletions
@@ -111,10 +111,15 @@ public object KotlinCompilerClient {
}
public fun compile(compilerService: CompileService, targetPlatform: CompileService.TargetPlatform, args: Array<out String>, out: OutputStream): Int {
val outStrm = RemoteOutputStreamServer(out)
return compilerService.remoteCompile(targetPlatform, args, CompilerCallbackServicesFacadeServer(), outStrm, CompileService.OutputFormat.PLAIN, outStrm)
public fun compile(compilerService: CompileService,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
out: OutputStream,
port: Int = SOCKET_ANY_FREE_PORT,
operationsTracer: RemoteOperationsTracer? = null
): Int {
val outStrm = RemoteOutputStreamServer(out, port = port)
return compilerService.remoteCompile(targetPlatform, args, CompilerCallbackServicesFacadeServer(port = port), outStrm, CompileService.OutputFormat.PLAIN, outStrm, operationsTracer)
}
@@ -124,16 +129,20 @@ public object KotlinCompilerClient {
callbackServices: CompilationServices,
compilerOut: OutputStream,
daemonOut: OutputStream,
profiler: Profiler = DummyProfiler()
port: Int = SOCKET_ANY_FREE_PORT,
profiler: Profiler = DummyProfiler(),
operationsTracer: RemoteOperationsTracer? = null
): Int = profiler.withMeasure(this) {
compileService.remoteIncrementalCompile(
targetPlatform,
args,
CompilerCallbackServicesFacadeServer(incrementalCompilationComponents = callbackServices.incrementalCompilationComponents,
compilationCancelledStatus = callbackServices.compilationCanceledStatus),
RemoteOutputStreamServer(compilerOut),
compilationCancelledStatus = callbackServices.compilationCanceledStatus,
port = port),
RemoteOutputStreamServer(compilerOut, port),
CompileService.OutputFormat.XML,
RemoteOutputStreamServer(daemonOut))
RemoteOutputStreamServer(daemonOut, port),
operationsTracer)
}
public val COMPILE_DAEMON_CLIENT_OPTIONS_PROPERTY: String = "kotlin.daemon.client.options"
@@ -207,7 +216,7 @@ public object KotlinCompilerClient {
val memBefore = daemon.getUsedMemory() / 1024
val startTime = System.nanoTime()
val res = daemon.remoteCompile(CompileService.TargetPlatform.JVM, filteredArgs.toArrayList().toTypedArray(), servicesFacade, outStrm, CompileService.OutputFormat.PLAIN, outStrm)
val res = daemon.remoteCompile(CompileService.TargetPlatform.JVM, filteredArgs.toArrayList().toTypedArray(), servicesFacade, outStrm, CompileService.OutputFormat.PLAIN, outStrm, null)
val endTime = System.nanoTime()
println("Compilation result code: $res")
@@ -46,7 +46,9 @@ public interface CompileService : Remote {
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
outputFormat: OutputFormat, serviceOutputStream: RemoteOutputStream
outputFormat: OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): Int
@Throws(RemoteException::class)
@@ -56,6 +58,7 @@ public interface CompileService : Remote {
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
compilerOutputFormat: OutputFormat,
serviceOutputStream: RemoteOutputStream
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): Int
}
@@ -21,8 +21,12 @@ import java.io.Serializable
import java.net.InetAddress
import java.net.ServerSocket
import java.net.Socket
import java.rmi.RemoteException
import java.rmi.registry.LocateRegistry
import java.rmi.registry.Registry
import java.rmi.server.RMIClientSocketFactory
import java.rmi.server.RMIServerSocketFactory
import java.util.*
public val SOCKET_ANY_FREE_PORT = 0
@@ -70,4 +74,22 @@ public object LoopbackNetworkInterface {
}
private val portSelectionRng = Random()
public fun findPortAndCreateRegistry(attempts: Int, portRangeStart: Int, portRangeEnd: Int) : Pair<Registry, Int> {
var i = 0
var lastException: RemoteException? = null
while (i++ < attempts) {
val port = portSelectionRng.nextInt(portRangeEnd - portRangeStart) + portRangeStart
try {
return Pair(LocateRegistry.createRegistry(port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory), port)
}
catch (e: RemoteException) {
// assuming that the port is already taken
lastException = e
}
}
throw IllegalStateException("Cannot find free port in $attempts attempts", lastException)
}
@@ -0,0 +1,29 @@
/*
* 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.rmi.Remote
import java.rmi.RemoteException
public interface RemoteOperationsTracer : Remote {
@Throws(RemoteException::class)
public fun before(id: String)
@Throws(RemoteException::class)
public fun after(id: String)
}
@@ -16,18 +16,17 @@
package org.jetbrains.kotlin.rmi
import java.io.IOException
import java.rmi.Remote
import java.rmi.RemoteException
public interface RemoteOutputStream : Remote {
@Throws(IOException::class, RemoteException::class)
@Throws(RemoteException::class)
public fun close()
@Throws(IOException::class, RemoteException::class)
@Throws(RemoteException::class)
public fun write(data: ByteArray, offset: Int, length: Int)
@Throws(IOException::class, RemoteException::class)
@Throws(RemoteException::class)
public fun write(dataByte: Int)
}
@@ -26,9 +26,6 @@ import java.io.OutputStream
import java.io.PrintStream
import java.lang.management.ManagementFactory
import java.net.URLClassLoader
import java.rmi.RemoteException
import java.rmi.registry.LocateRegistry
import java.rmi.registry.Registry
import java.text.SimpleDateFormat
import java.util.*
import java.util.jar.Manifest
@@ -121,7 +118,7 @@ public object CompileDaemon {
//
// setDaemonPpermissions(daemonOptions.port)
val (registry, port) = createRegistry(COMPILE_DAEMON_FIND_PORT_ATTEMPTS)
val (registry, port) = findPortAndCreateRegistry(COMPILE_DAEMON_FIND_PORT_ATTEMPTS, COMPILE_DAEMON_PORTS_RANGE_START, COMPILE_DAEMON_PORTS_RANGE_END)
val runFileDir = File(if (daemonOptions.runFilesPath.isBlank()) COMPILE_DAEMON_DEFAULT_RUN_DIR_PATH else daemonOptions.runFilesPath)
runFileDir.mkdirs()
val runFile = File(runFileDir,
@@ -199,23 +196,4 @@ public object CompileDaemon {
throw e
}
}
val random = Random()
private fun createRegistry(attempts: Int) : Pair<Registry, Int> {
var i = 0
var lastException: RemoteException? = null
while (i++ < attempts) {
val port = random.nextInt(COMPILE_DAEMON_PORTS_RANGE_END - COMPILE_DAEMON_PORTS_RANGE_START) + COMPILE_DAEMON_PORTS_RANGE_START
try {
return Pair(LocateRegistry.createRegistry(port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory), port)
}
catch (e: RemoteException) {
// assuming that the port is already taken
lastException = e
}
}
throw IllegalStateException("Cannot find free port in $attempts attempts", lastException)
}
}
@@ -76,9 +76,11 @@ class CompileServiceImpl(
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
outputFormat: CompileService.OutputFormat, serviceOutputStream: RemoteOutputStream
outputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): Int =
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream, profiler ->
doCompile(args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, profiler ->
when (outputFormat) {
CompileService.OutputFormat.PLAIN -> compiler[targetPlatform].exec(printStream, *args)
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, profiler), *args)
@@ -90,9 +92,10 @@ class CompileServiceImpl(
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
compilerOutputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): Int =
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream, profiler ->
doCompile(args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, profiler ->
when (compilerOutputFormat) {
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, profiler), *args)
@@ -137,8 +140,13 @@ class CompileServiceImpl(
alive = true
}
private fun doCompile(args: Array<out String>, compilerMessagesStreamProxy: RemoteOutputStream, serviceOutputStreamProxy: RemoteOutputStream, body: (PrintStream, Profiler) -> ExitCode): Int =
private fun doCompile(args: Array<out String>,
compilerMessagesStreamProxy: RemoteOutputStream,
serviceOutputStreamProxy: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?,
body: (PrintStream, Profiler) -> ExitCode): Int =
ifAlive {
operationsTracer?.before("compile")
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler), 4096))
val serviceOutputStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler), 4096))
@@ -152,6 +160,7 @@ class CompileServiceImpl(
finally {
serviceOutputStream.flush()
compilerMessagesStream.flush()
operationsTracer?.after("compile")
}
}