package org.sonar.application.process;
import java.io.File;
+import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
Map<String, String> settingsMap = new EsSettings(this.settings.getProps()).build();
File logDir = new File(settingsMap.get("path.logs"));
+ File confDir = new File(settingsMap.get("path.conf"));
+ Path jvmOptionsFile = confDir.toPath().resolve("jvm.options");
EsCommand res = new EsCommand(ProcessId.ELASTICSEARCH)
.setWorkDir(executable.getParentFile().getParentFile())
.setExecutable(executable)
- .setConfDir(new File(settingsMap.get("path.conf")))
+ .setConfDir(confDir)
.setLog4j2Properties(buildLog4j2Properties(logDir))
.setArguments(this.settings.getProps().rawProperties())
.setClusterName(settingsMap.get("cluster.name"))
.setHost(settingsMap.get("network.host"))
- .setPort(Integer.valueOf(settingsMap.get("transport.tcp.port")));
+ .setPort(Integer.valueOf(settingsMap.get("transport.tcp.port")))
+ .addJvmOption(settings.getProps().nonNullValue(ProcessProperties.SEARCH_JAVA_OPTS))
+ .addJvmOption(settings.getProps().nonNullValue(ProcessProperties.SEARCH_JAVA_ADDITIONAL_OPTS))
+ .setJvmOptionsFile(jvmOptionsFile)
+ .setEnvVariable("ES_JVM_OPTIONS", jvmOptionsFile.toString())
+ ;
settingsMap.forEach((key, value) -> res.addEsOption("-E" + key + "=" + value));
package org.sonar.application.process;
import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
private int port;
private Properties log4j2Properties;
private List<String> esOptions = new ArrayList<>();
+ private List<String> jvmOptions = new ArrayList<>();
+ private Path jvmOptionsFile;
public EsCommand(ProcessId id) {
super(id);
}
return this;
}
+
+ public List<String> getJvmOptions() {
+ return jvmOptions;
+ }
+
+ public EsCommand addJvmOption(String s) {
+ if (!s.isEmpty()) {
+ jvmOptions.add(s);
+ }
+ return this;
+ }
+
+ public Path getJvmOptionsFile() {
+ return jvmOptionsFile;
+ }
+
+ public EsCommand setJvmOptionsFile(Path jvmOptionsFile) {
+ this.jvmOptionsFile = jvmOptionsFile;
+ return this;
+ }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProcessLauncherImpl implements ProcessLauncher {
private static final Logger LOG = LoggerFactory.getLogger(ProcessLauncherImpl.class);
+ public static final String ELASTICSEARCH_JVM_OPTIONS_HEADER = "# This file has been automatically generated by SonarQube during startup.\n" +
+ "# Please use the sonar.search.javaOpts in sonar.properties to specify jvm options for Elasticsearch\n" +
+ "\n" +
+ "# DO NOT EDIT THIS FILE\n" +
+ "\n";
private final File tempDir;
private final AllProcessesCommands allProcessesCommands;
commands.add(esCommand.getExecutable().getAbsolutePath());
commands.addAll(esCommand.getEsOptions());
+ writeJvmOptions(esCommand);
+
return create(esCommand, commands);
}
+ private void writeJvmOptions(EsCommand esCommand) {
+ Path jvmOptionsFile = esCommand.getJvmOptionsFile();
+ String jvmOptions = esCommand.getJvmOptions()
+ .stream()
+ .map(s -> s.split(" (?=-)"))// FIXME this pattern does not allow escaping
+ .flatMap(Arrays::stream)
+ .collect(Collectors.joining("\n"));
+ String jvmOptionsContent = ELASTICSEARCH_JVM_OPTIONS_HEADER + jvmOptions;
+ try {
+ Files.write(jvmOptionsFile, jvmOptionsContent.getBytes(Charset.forName("UTF-8")));
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write Elasticsearch jvm options file", e);
+ }
+ }
+
private ProcessBuilder create(JavaCommand javaCommand) {
List<String> commands = new ArrayList<>();
commands.add(buildJavaPath());
Properties defaults = new Properties();
defaults.put(SEARCH_HOST, InetAddress.getLoopbackAddress().getHostAddress());
defaults.put(SEARCH_PORT, "9001");
- defaults.put(SEARCH_JAVA_OPTS, "-Xmx1G -Xms256m -Xss256k -Djna.nosys=true " +
- "-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly " +
- "-XX:+HeapDumpOnOutOfMemoryError");
+ defaults.put(SEARCH_JAVA_OPTS, "-Xms1g" +
+ " -Xmx1g" +
+ " -XX:+UseConcMarkSweepGC" +
+ " -XX:CMSInitiatingOccupancyFraction=75" +
+ " -XX:+UseCMSInitiatingOccupancyOnly" +
+ " -XX:+AlwaysPreTouch" +
+ " -server" +
+ " -Xss1m" +
+ " -Djava.awt.headless=true" +
+ " -Dfile.encoding=UTF-8" +
+ " -Djna.nosys=true" +
+ " -Djdk.io.permissionsUseCanonicalPath=true" +
+ " -Dio.netty.noUnsafe=true" +
+ " -Dio.netty.noKeySetOptimization=true" +
+ " -Dio.netty.recycler.maxCapacityPerThread=0" +
+ " -Dlog4j.shutdownHookEnabled=false" +
+ " -Dlog4j2.disable.jmx=true" +
+ " -Dlog4j.skipJansi=true" +
+ " -XX:+HeapDumpOnOutOfMemoryError");
defaults.put(SEARCH_JAVA_ADDITIONAL_OPTS, "");
defaults.put(PATH_DATA, "data");
#--------------------------------------------------------------------------------------------------
# ELASTICSEARCH
# Elasticsearch is used to facilitate fast and accurate information retrieval.
-# It is executed in a dedicated Java process. Default heap size is 1Gb.
+# It is executed in a dedicated Java process. Default heap size is 2Gb.
# JVM options of Elasticsearch process
-# Recommendations:
-#
-# Use HotSpot Server VM. The property -server should be added if server mode
-# is not enabled by default on your environment:
-# http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html
-#
-#sonar.search.javaOpts=-Xmx1G -Xms256m -Xss256k -Djna.nosys=true \
-# -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 \
-# -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError
+#sonar.search.javaOpts=-Xms2g \
+# -Xmx2g \
+# -XX:+UseConcMarkSweepGC \
+# -XX:CMSInitiatingOccupancyFraction=75 \
+# -XX:+UseCMSInitiatingOccupancyOnly \
+# -XX:+AlwaysPreTouch \
+# -server \
+# -Xss1m \
+# -Djava.awt.headless=true \
+# -Dfile.encoding=UTF-8 \
+# -Djna.nosys=true \
+# -Djdk.io.permissionsUseCanonicalPath=true \
+# -Dio.netty.noUnsafe=true \
+# -Dio.netty.noKeySetOptimization=true \
+# -Dio.netty.recycler.maxCapacityPerThread=0 \
+# -Dlog4j.shutdownHookEnabled=false \
+# -Dlog4j2.disable.jmx=true \
+# -Dlog4j.skipJansi=true \
+# -XX:+HeapDumpOnOutOfMemoryError
# Same as previous property, but allows to not repeat all other settings like -Xmx
#sonar.search.javaAdditionalOpts=