From 6f217001fef8c5d0f25031633fe89dd4e50a4e4e Mon Sep 17 00:00:00 2001 From: Daniel Schwarz Date: Fri, 4 Aug 2017 14:09:07 +0200 Subject: [PATCH] SONAR-8798 pass sonar.search.javaOpts in a file to ES --- .../process/CommandFactoryImpl.java | 12 ++++++-- .../sonar/application/process/EsCommand.java | 23 ++++++++++++++ .../process/ProcessLauncherImpl.java | 27 +++++++++++++++++ .../org/sonar/process/ProcessProperties.java | 22 ++++++++++++-- .../src/main/assembly/conf/sonar.properties | 30 ++++++++++++------- 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/CommandFactoryImpl.java b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/CommandFactoryImpl.java index 093b44ef20d..fdb296347a7 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/CommandFactoryImpl.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/CommandFactoryImpl.java @@ -20,6 +20,7 @@ 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; @@ -64,15 +65,22 @@ public class CommandFactoryImpl implements CommandFactory { Map 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)); diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/EsCommand.java b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/EsCommand.java index 5557978388b..3e787eb6736 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/EsCommand.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/EsCommand.java @@ -20,6 +20,7 @@ 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; @@ -33,6 +34,8 @@ public class EsCommand extends AbstractCommand { private int port; private Properties log4j2Properties; private List esOptions = new ArrayList<>(); + private List jvmOptions = new ArrayList<>(); + private Path jvmOptionsFile; public EsCommand(ProcessId id) { super(id); @@ -102,4 +105,24 @@ public class EsCommand extends AbstractCommand { } return this; } + + public List 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; + } } diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java index f6817b6ab92..b849c5f52c9 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java @@ -23,12 +23,17 @@ import java.io.File; 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; @@ -43,6 +48,11 @@ import static org.sonar.process.ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT; 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; @@ -125,9 +135,26 @@ public class ProcessLauncherImpl implements ProcessLauncher { 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 commands = new ArrayList<>(); commands.add(buildJavaPath()); diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java index 959788fb933..c2f61f644e9 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java @@ -121,9 +121,25 @@ public class ProcessProperties { 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"); diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties index 4b167d014e7..5b5c6e054ec 100644 --- a/sonar-application/src/main/assembly/conf/sonar.properties +++ b/sonar-application/src/main/assembly/conf/sonar.properties @@ -184,18 +184,28 @@ #-------------------------------------------------------------------------------------------------- # 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= -- 2.39.5