revert in-process compile server

This commit is contained in:
peter
2012-04-16 15:36:11 +02:00
parent b5fef3b943
commit f5cecddbb8
5 changed files with 97 additions and 145 deletions
@@ -91,7 +91,7 @@ public class CompileServerManager implements ApplicationComponent{
private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server";
private static final String LOGGER_CONFIG = "log.xml";
private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
private volatile ServerWrapper myProcessHandler;
private volatile OSProcessHandler myProcessHandler;
private final File mySystemDirectory;
@Nullable
private volatile CompileServerClient myClient;
@@ -335,7 +335,7 @@ public class CompileServerManager implements ApplicationComponent{
public RequestFuture submitCompilationTask(final Project project, final boolean isRebuild, final boolean isMake,
final Collection<String> modules, final Collection<String> artifacts,
final Collection<String> paths,
final Map<String, String> _userData, final JpsServerResponseHandler handler) {
final Map<String, String> userData, final JpsServerResponseHandler handler) {
final String projectId = getProjectPath(project);
final Ref<RequestFuture> futureRef = new Ref<RequestFuture>(null);
final RunnableFuture future = myTaskExecutor.submit(new Runnable() {
@@ -344,16 +344,9 @@ public class CompileServerManager implements ApplicationComponent{
try {
final CompileServerClient client = ensureServerRunningAndClientConnected(true);
if (client != null) {
final Map<String, String> userData = new LinkedHashMap<String, String>();
if (!isRebuild) { //todo pass user data on rebuild as well?
userData.putAll(_userData);
}
if (Registry.is("compiler.server.use.external.javac.process")) {
userData.put(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION, "true");
}
final RequestFuture requestFuture = isRebuild ?
client.sendRebuildRequest(projectId, handler, userData) :
client.sendCompileRequest(isMake, projectId, modules, artifacts, paths, userData, handler);
client.sendRebuildRequest(projectId, handler, userData) :
client.sendCompileRequest(isMake, projectId, modules, artifacts, paths, userData, handler);
futureRef.set(requestFuture);
}
else {
@@ -397,9 +390,9 @@ public class CompileServerManager implements ApplicationComponent{
// executed in one thread at a time
@Nullable
private CompileServerClient ensureServerRunningAndClientConnected(boolean forceRestart) throws Throwable {
final ServerWrapper ph = myProcessHandler;
final OSProcessHandler ph = myProcessHandler;
final CompileServerClient cl = myClient;
final boolean processNotRunning = ph == null || ph.isDead();
final boolean processNotRunning = ph == null || ph.isProcessTerminated() || ph.isProcessTerminating();
final boolean clientNotConnected = cl == null || !cl.isConnected();
if (processNotRunning || clientNotConnected) {
@@ -412,13 +405,68 @@ public class CompileServerManager implements ApplicationComponent{
return null;
}
final File workDirectory = new File(mySystemDirectory, COMPILE_SERVER_SYSTEM_ROOT);
workDirectory.mkdirs();
ensureLogConfigExists(workDirectory);
final int port = NetUtils.findAvailableSocketPort();
final long serverPingInterval = Registry.intValue("compiler.server.ping.interval", -1) * 1000L;
ServerWrapper wrapper = Registry.is("compiler.server.in.process") ? launchServerThread(workDirectory, port) : launchServerProcess(port, serverPingInterval, workDirectory);
final long serverPingInterval = Registry.intValue("compiler.server.ping.interval", -1) * 1000L;
final Process process = launchServer(port, serverPingInterval);
final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
@Override
protected boolean shouldDestroyProcessRecursively() {
return true;
}
};
final StringBuilder serverStartMessage = new StringBuilder();
final Semaphore semaphore = new Semaphore();
semaphore.down();
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
// re-translate server's output to idea.log
final String text = event.getText();
if (!StringUtil.isEmpty(text)) {
LOG.info("COMPILE_SERVER [" +outputType.toString() +"]: "+ text.trim());
}
}
});
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
try {
processHandler.removeProcessListener(this);
}
finally {
semaphore.up();
}
}
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (outputType == ProcessOutputTypes.STDERR) {
try {
final String text = event.getText();
if (text != null) {
if (text.contains(Server.SERVER_SUCCESS_START_MESSAGE) || text.contains(Server.SERVER_ERROR_START_MESSAGE)) {
processHandler.removeProcessListener(this);
}
if (serverStartMessage.length() > 0) {
serverStartMessage.append("\n");
}
serverStartMessage.append(text);
}
}
finally {
semaphore.up();
}
}
}
});
processHandler.startNotify();
semaphore.waitFor();
final String startupMsg = serverStartMessage.toString();
if (!startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) {
throw new Exception("Server startup failed: " + startupMsg);
}
CompileServerClient client = new CompileServerClient(serverPingInterval, myAsyncExec);
boolean connected = false;
@@ -427,90 +475,19 @@ public class CompileServerManager implements ApplicationComponent{
if (connected) {
final RequestFuture setupFuture = sendSetupRequest(client);
setupFuture.waitFor();
myProcessHandler = wrapper;
myProcessHandler = processHandler;
myClient = client;
}
}
finally {
if (!connected) {
shutdownServer(cl, wrapper);
shutdownServer(cl, processHandler);
}
}
}
return myClient;
}
private static ServerWrapper launchServerThread(final File workDirectory, final int port) {
final Server server = new Server(workDirectory, Registry.is("compiler.server.use.memory.temp.cache"));
//todo hostname
server.start(port);
return new ServerWrapper(null, server);
}
private ServerWrapper launchServerProcess(int port, long serverPingInterval, File workDirectory) throws Exception {
final Process process = launchServer(port, serverPingInterval, workDirectory);
final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
@Override
protected boolean shouldDestroyProcessRecursively() {
return true;
}
};
final StringBuilder serverStartMessage = new StringBuilder();
final Semaphore semaphore = new Semaphore();
semaphore.down();
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
// re-translate server's output to idea.log
final String text = event.getText();
if (!StringUtil.isEmpty(text)) {
LOG.info("COMPILE_SERVER [" +outputType.toString() +"]: "+ text.trim());
}
}
});
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
try {
processHandler.removeProcessListener(this);
}
finally {
semaphore.up();
}
}
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (outputType == ProcessOutputTypes.STDERR) {
try {
final String text = event.getText();
if (text != null) {
if (text.contains(Server.SERVER_SUCCESS_START_MESSAGE) || text.contains(Server.SERVER_ERROR_START_MESSAGE)) {
processHandler.removeProcessListener(this);
}
if (serverStartMessage.length() > 0) {
serverStartMessage.append("\n");
}
serverStartMessage.append(text);
}
}
finally {
semaphore.up();
}
}
}
});
processHandler.startNotify();
semaphore.waitFor();
final String startupMsg = serverStartMessage.toString();
if (!startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) {
throw new Exception("Server startup failed: " + startupMsg);
}
return new ServerWrapper(processHandler, null);
}
private static RequestFuture sendSetupRequest(final @NotNull CompileServerClient client) throws Exception {
final Map<String, String> data = new HashMap<String, String>();
@@ -593,7 +570,7 @@ public class CompileServerManager implements ApplicationComponent{
// commandLine.add((launcherUsed? "-J" : "") + "-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + CharsetToolkit.getDefaultSystemCharset().name());
//}
private Process launchServer(final int port, long pingInterval, File workDirectory) throws ExecutionException {
private Process launchServer(final int port, long pingInterval) throws ExecutionException {
// validate tools.jar presence
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
if (systemCompiler == null) {
@@ -642,6 +619,9 @@ public class CompileServerManager implements ApplicationComponent{
if (Registry.is("compiler.server.use.memory.temp.cache")) {
cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION + "=true");
}
if (Registry.is("compiler.server.use.external.javac.process")) {
cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION + "=true");
}
cmdLine.addParameter("-D"+ GlobalOptions.HOSTNAME_OPTION + "=" + NetUtils.getLocalHostString());
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
@@ -672,6 +652,10 @@ public class CompileServerManager implements ApplicationComponent{
cmdLine.addParameter(org.jetbrains.jps.server.Server.class.getName());
cmdLine.addParameter(Integer.toString(port));
final File workDirectory = new File(mySystemDirectory, COMPILE_SERVER_SYSTEM_ROOT);
workDirectory.mkdirs();
ensureLogConfigExists(workDirectory);
cmdLine.addParameter(FileUtil.toSystemIndependentName(workDirectory.getPath()));
cmdLine.setWorkDirectory(workDirectory);
@@ -711,7 +695,7 @@ public class CompileServerManager implements ApplicationComponent{
shutdownServer(myClient, myProcessHandler);
}
private static void shutdownServer(final CompileServerClient client, final ServerWrapper processHandler) {
private static void shutdownServer(final CompileServerClient client, final OSProcessHandler processHandler) {
try {
if (client != null && client.isConnected()) {
final Future future = client.sendShutdownRequest();
@@ -884,28 +868,4 @@ public class CompileServerManager implements ApplicationComponent{
}
}
}
private static class ServerWrapper {
final @Nullable OSProcessHandler myHandler;
final @Nullable Server myServer;
ServerWrapper(OSProcessHandler handler, Server server) {
myHandler = handler;
myServer = server;
}
public void destroyProcess() {
if (myHandler != null) {
myHandler.destroyProcess();
} else if (myServer != null) {
myServer.stop();
}
}
public boolean isDead() {
return myHandler != null && (myHandler.isProcessTerminated() || myHandler.isProcessTerminating()) ||
myServer != null && myServer.isStopped();
}
}
}
@@ -7,13 +7,13 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.io.MappingFailedException;
import com.intellij.util.io.PersistentEnumerator;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.*;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.api.SharedThreadPool;
import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
import org.jetbrains.jps.incremental.java.JavaBuilder;
import org.jetbrains.jps.incremental.java.JavaBuilderLogger;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
@@ -164,7 +164,7 @@ public class IncProjectBuilder {
return context;
}
private static void flushContext(@Nullable CompileContext context) {
private static void flushContext(CompileContext context) {
if (context != null) {
context.getTimestampStorage().force();
context.getDataManager().flush(false);
@@ -181,16 +181,14 @@ public class IncProjectBuilder {
}
ExternalJavacDescriptor.KEY.set(context, null);
}
if (context == null || context.getBuilderParameter(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null) {
cleanupJavacNameTable();
}
cleanupJavacNameTable();
}
private static boolean ourClenupFailed = false;
private static void cleanupJavacNameTable() {
try {
if (!ourClenupFailed) {
if (JavaBuilder.USE_EMBEDDED_JAVAC && !ourClenupFailed) {
final Field freelistField = Class.forName("com.sun.tools.javac.util.Name$Table").getDeclaredField("freelist");
freelistField.setAccessible(true);
freelistField.set(null, com.sun.tools.javac.util.List.nil());
@@ -56,6 +56,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static final String FORMS_BUILDER_NAME = "forms";
private static final String JAVA_EXTENSION = ".java";
private static final String FORM_EXTENSION = ".form";
public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
public static final FileFilter JAVA_SOURCES_FILTER = new FileFilter() {
public boolean accept(File file) {
@@ -385,7 +386,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink);
try {
final boolean rc;
if (context.getBuilderParameter(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null) {
if (USE_EMBEDDED_JAVAC) {
rc = JavacMain.compile(
options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus()
);
@@ -70,7 +70,7 @@ public class Server {
private final ScheduledExecutorService myScheduler;
private final ServerMessageHandler myMessageHandler;
public Server(File systemDir, boolean cachesInMemory) {
public Server(File systemDir) {
Utils.setSystemRoot(systemDir);
final ExecutorService threadPool = Executors.newCachedThreadPool();
myScheduler = ConcurrencyUtil.newSingleScheduledThreadExecutor("Client activity checker", Thread.MIN_PRIORITY);
@@ -105,17 +105,6 @@ public class Server {
);
}
};
ServerState.getInstance().setKeepTempCachesInMemory(cachesInMemory);
Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") {
public void run() {
try {
myMessageHandler.cancelAllBuildsAndClearState();
}
finally {
Server.this.stop();
}
}
});
}
public void start(int listenPort) {
@@ -192,10 +181,6 @@ public class Server {
myLastPingTime = System.currentTimeMillis();
}
public boolean isStopped() {
return myScheduler.isShutdown();
}
public static void main(String[] args) {
try {
int port = DEFAULT_SERVER_PORT;
@@ -212,10 +197,21 @@ public class Server {
systemDir = new File(args[1]);
}
final Server server = new Server(systemDir, System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null);
final Server server = new Server(systemDir);
Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") {
public void run() {
try {
server.myMessageHandler.cancelAllBuildsAndClearState();
}
finally {
server.stop();
}
}
});
initLoggers();
server.start(port);
ServerState.getInstance().setKeepTempCachesInMemory(System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null);
System.out.println("Server classpath: " + System.getProperty("java.class.path"));
System.err.println(SERVER_SUCCESS_START_MESSAGE + port);
@@ -151,9 +151,6 @@ compiler.server.use.external.javac.process.description=Run javac compiler in ext
compiler.server.ping.interval=5
compiler.server.ping.interval.description=Interval in seconds between ping requests the IDE periodically sends to server. If server does not receive pings for some time, it shuts down. Specify -1 to disable this feature.
compiler.server.in.process=false
compiler.server.in.process.description=Launch compiler server in IDEA process
compiler.server.debug.port=-1
#compiler.server.javac.debug.port=-1