8256308: Send arguments to javac server in a config file

Reviewed-by: erikj, jfranck
This commit is contained in:
Magnus Ihse Bursie 2020-11-24 11:13:09 +00:00
parent 8f7caa4353
commit 9e4944f7b6
3 changed files with 96 additions and 77 deletions

View File

@ -177,6 +177,12 @@ define SetupJavaCompilationBody
$$(error Must specify BIN (in $1))
endif
ifneq ($$($1_MODULE), )
$1_MODULE_SUBDIR := /$$($1_MODULE)
endif
$1_SAFE_NAME := $$(strip $$(subst /,_, $1))
ifeq ($$($1_SMALL_JAVA), )
# If unspecified, default to true
$1_SMALL_JAVA := true
@ -215,18 +221,35 @@ define SetupJavaCompilationBody
ifeq ($$(ENABLE_JAVAC_SERVER)+$$($1_CLASSPATH), true+)
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -m jdk.compiler.interim/com.sun.tools.sjavac.Main
# How to launch the server. This must use JAVA_DETACH, which is the "big" java
# with an ability to detach from fixpath (on Windows)
# This will be executed by the client, if needed.
$1_JAVAC_SERVER_CMD := $$(JAVA_DETACH) $$($1_JAVA_FLAGS) $$($1_JAVAC)
$1_ESCAPED_CMD := $$(subst $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_JAVAC_SERVER_CMD))))
# Create a configuration file with the needed information for the javac
# server to function properly.
$1_JAVAC_SERVER_CONFIG := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$$($1_SAFE_NAME)-server.conf
# The port file contains the tcp/ip on which the server listens
# The portfile contains the tcp/ip on which the server listens
# and the cookie necessary to talk to the server.
$1_JAVA_SERVER_FLAGS := --server:portfile=$$(JAVAC_SERVER_DIR)/server.port,sjavac=$$($1_ESCAPED_CMD)
$1_JAVAC_PORT_FILE := $$(JAVAC_SERVER_DIR)/server.port
# Always use small to launch client
$1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC) $$($1_JAVA_SERVER_FLAGS)
# The servercmd specified how to launch the server. This must use
# JAVA_DETACH, which is the "big" java with an ability to detach from
# fixpath (on Windows) This will be executed by the client, if needed.
$1_JAVAC_SERVER_CMD := $$(JAVA_DETACH) $$($1_JAVA_FLAGS) $$($1_JAVAC)
$1_CONFIG_VARDEPS := $$($1_JAVAC_PORT_FILE) $$($1_JAVAC_SERVER_CMD)
$1_CONFIG_VARDEPS_FILE := $$(call DependOnVariable, $1_CONFIG_VARDEPS, \
$$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1.config_vardeps)
ifeq ($(call isBuildOs, windows), true)
$1_ECHO_COMMAND := $(FIXPATH) cmd /c echo
else
$1_ECHO_COMMAND := $(ECHO)
endif
$$($1_JAVAC_SERVER_CONFIG): $$($1_CONFIG_VARDEPS_FILE)
$$($1_ECHO_COMMAND) portfile=$$($1_JAVAC_PORT_FILE) > $$@
$$($1_ECHO_COMMAND) servercmd=$$($1_JAVAC_SERVER_CMD) >> $$@
# Always use small java to launch client
$1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC) \
--server:conf=$$($1_JAVAC_SERVER_CONFIG)
else
# No javac server
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -m jdk.compiler.interim/com.sun.tools.javac.Main
@ -263,10 +286,6 @@ define SetupJavaCompilationBody
$1_FLAGS += -cp $$(call PathList, $$($1_CLASSPATH))
endif
ifneq ($$($1_MODULE), )
$1_MODULE_SUBDIR := /$$($1_MODULE)
endif
# Make sure the dirs exist, or that one of the EXTRA_FILES, that may not
# exist yet, is in it.
$$(foreach d, $$($1_SRC), \
@ -331,9 +350,6 @@ define SetupJavaCompilationBody
$$(error No source files found for $1)
endif
else
$1_SAFE_NAME := $$(strip $$(subst /,_, $1))
# All files below META-INF are always copied.
$1_ALL_COPIES := $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS))
# Find all files to be copied from source to bin.
@ -442,7 +458,7 @@ define SetupJavaCompilationBody
# Do the actual compilation
$$($1_COMPILE_TARGET): $$($1_SRCS) $$($1_FILELIST) $$($1_DEPENDS) \
$$($1_VARDEPS_FILE) $$($1_EXTRA_DEPS)
$$($1_VARDEPS_FILE) $$($1_EXTRA_DEPS) $$($1_JAVAC_SERVER_CONFIG)
$$(call MakeDir, $$(@D))
$$(call ExecuteWithLog, $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$$($1_SAFE_NAME)_batch, \
$$($1_JAVAC_CMD) $$($1_FLAGS) \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -79,15 +79,23 @@ public class Util {
return extractStringOption(opName, s, null);
}
public static String extractStringOption(String opName, String s, String deflt) {
private static String extractStringOptionWithDelimiter(String opName, String s, String deflt, char delimiter) {
int p = s.indexOf(opName+"=");
if (p == -1) return deflt;
p+=opName.length()+1;
int pe = s.indexOf(',', p);
int pe = s.indexOf(delimiter, p);
if (pe == -1) pe = s.length();
return s.substring(p, pe);
}
public static String extractStringOption(String opName, String s, String deflt) {
return extractStringOptionWithDelimiter(opName, s, deflt, ',');
}
public static String extractStringOptionLine(String opName, String s, String deflt) {
return extractStringOptionWithDelimiter(opName, s, deflt, '\n').strip();
}
public static boolean extractBooleanOption(String opName, String s, boolean deflt) {
String str = extractStringOption(opName, s);
return "true".equals(str) ? true

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,9 @@ import java.io.Reader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -42,15 +45,11 @@ import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.options.OptionHelper;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.server.CompilationSubResult;
import com.sun.tools.sjavac.server.PortFile;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.SjavacServer;
import static java.util.stream.Collectors.joining;
/**
* Sjavac implementation that delegates requests to a SjavacServer.
*
@ -61,59 +60,58 @@ import static java.util.stream.Collectors.joining;
*/
public class SjavacClient implements Sjavac {
// The id can perhaps be used in the future by the javac server to reuse the
// JavaCompiler instance for several compiles using the same id.
private final String id;
private final PortFile portFile;
private PortFile portFile;
// Default keepalive for server is 120 seconds.
// I.e. it will accept 120 seconds of inactivity before quitting.
private final int keepalive;
private final int poolsize;
// The sjavac option specifies how the server part of sjavac is spawned.
// If you have the experimental sjavac in your path, you are done. If not, you have
// to point to a com.sun.tools.sjavac.Main that supports --startserver
// for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
private final String sjavacForkCmd;
// The servercmd option specifies how the server part of sjavac is spawned.
// It should point to a com.sun.tools.sjavac.Main that supports --startserver
private String serverCommand;
// Accept 120 seconds of inactivity before quitting.
private static final int KEEPALIVE = 120;
private static final int POOLSIZE = Runtime.getRuntime().availableProcessors();
// Wait 2 seconds for response, before giving up on javac server.
static int CONNECTION_TIMEOUT = 2000;
static int MAX_CONNECT_ATTEMPTS = 3;
static int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000;
// Store the server conf settings here.
private final String settings;
private static final int CONNECTION_TIMEOUT = 2000;
private static final int MAX_CONNECT_ATTEMPTS = 3;
private static final int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000;
public SjavacClient(Options options) {
String tmpServerConf = options.getServerConf();
String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
String tmpId = Util.extractStringOption("id", serverConf);
id = (tmpId!=null) ? tmpId : "id"+(((new java.util.Random()).nextLong())&Long.MAX_VALUE);
String defaultPortfile = options.getDestDir()
.resolve("javac_server")
.toAbsolutePath()
.toString();
String portfileName = Util.extractStringOption("portfile", serverConf, defaultPortfile);
portFile = SjavacServer.getPortFile(portfileName);
sjavacForkCmd = Util.extractStringOption("sjavac", serverConf, "sjavac");
int poolsize = Util.extractIntOption("poolsize", serverConf);
keepalive = Util.extractIntOption("keepalive", serverConf, 120);
String serverConf = options.getServerConf();
String configFile = Util.extractStringOption("conf", serverConf, "");
this.poolsize = poolsize > 0 ? poolsize : Runtime.getRuntime().availableProcessors();
settings = (serverConf.equals("")) ? "id="+id+",portfile="+portfileName : serverConf;
}
try {
List<String> configFileLines = Files.readAllLines(Path.of(configFile), StandardCharsets.UTF_8);
String configFileContent = String.join("\n", configFileLines);
/**
* Hand out the server settings.
* @return The server settings, possibly a default value.
*/
public String serverSettings() {
return settings;
String portfileName = Util.extractStringOptionLine("portfile", configFileContent, "");
if (portfileName.isEmpty()) {
Log.error("Configuration file missing value for 'portfile'");
portFile = null;
} else {
portFile = SjavacServer.getPortFile(portfileName);
}
String serverCommandString = Util.extractStringOptionLine("servercmd", configFileContent, "");
if (serverCommandString.isEmpty()) {
Log.error("Configuration file missing value for 'servercmd'");
serverCommand = null;
} else {
serverCommand = serverCommandString;
}
} catch (IOException e) {
Log.error("Cannot read configuration file " + configFile);
Log.debug(e);
portFile = null;
serverCommand = null;
}
}
@Override
public Result compile(String[] args) {
if (portFile == null || serverCommand == null) {
Log.error("Incorrect configuration, portfile and/or servercmd missing");
return Result.ERROR;
}
Result result = null;
try (Socket socket = tryConnect()) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
@ -176,7 +174,7 @@ public class SjavacClient implements Sjavac {
* Makes MAX_CONNECT_ATTEMPTS attempts to connect to server.
*/
private Socket tryConnect() throws IOException, InterruptedException {
makeSureServerIsRunning(portFile);
makeSureServerIsRunning();
int attempt = 0;
while (true) {
Log.debug("Trying to connect. Attempt " + (++attempt) + " of " + MAX_CONNECT_ATTEMPTS);
@ -206,7 +204,7 @@ public class SjavacClient implements Sjavac {
* Will return immediately if a server already seems to be running,
* otherwise fork a new server and block until it seems to be running.
*/
private void makeSureServerIsRunning(PortFile portFile)
private void makeSureServerIsRunning()
throws IOException, InterruptedException {
if (portFile.exists()) {
@ -221,10 +219,7 @@ public class SjavacClient implements Sjavac {
}
// Fork a new server and wait for it to start
SjavacClient.fork(sjavacForkCmd,
portFile,
poolsize,
keepalive);
startNewServer();
}
@Override
@ -235,14 +230,14 @@ public class SjavacClient implements Sjavac {
/*
* Fork a server process process and wait for server to come around
*/
public static void fork(String sjavacCmd, PortFile portFile, int poolsize, int keepalive)
public void startNewServer()
throws IOException, InterruptedException {
List<String> cmd = new ArrayList<>();
cmd.addAll(Arrays.asList(OptionHelper.unescapeCmdArg(sjavacCmd).split(" ")));
cmd.addAll(Arrays.asList(serverCommand.split(" ")));
cmd.add("--startserver:"
+ "portfile=" + portFile.getFilename()
+ ",poolsize=" + poolsize
+ ",keepalive="+ keepalive);
+ ",poolsize=" + POOLSIZE
+ ",keepalive="+ KEEPALIVE);
Process serverProcess;
Log.debug("Starting server. Command: " + String.join(" ", cmd));