/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.utils; import java.io.File; import java.io.FileWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableSet; import java.util.Set; import java.util.TreeMap; import org.voltdb.BackendTarget; import org.voltdb.StartAction; import org.voltdb.VoltDB; import org.voltdb.common.Constants; import org.voltdb.probe.MeshProber; import com.google_voltpatches.common.base.Joiner; import com.google_voltpatches.common.collect.ImmutableSortedSet; // VoltDB.Configuration represents all of the VoltDB command line parameters. // Extend that to include test-only parameters, the JVM parameters // and a serialization function that produces a legitimate command line. public class CommandLine extends VoltDB.Configuration { // Values for garbage collection roll-over configuration. For now statically defined, but // in the future we could configure them from the UI or VEM command line. public static final String VEM_GC_ROLLOVER_FILE_SIZE = "256K"; public static final String VEM_GC_ROLLOVER_FILE_COUNT = "16"; public static final String VEM_GC_ROLLOVER_FILE_NAME = "volt_gc.log"; /* * A tag value generated by VEM that is set as a Java property. * It allows VEM to know that it is connecting to the correct process * with JMX */ private String m_vemTag = null; public String m_modeOverrideForTest = null; public static final String VEM_TAG_PROPERTY = "org.voltdb.vemtag"; public CommandLine(StartAction start_action) { m_startAction = start_action; } // Copy ctor. public CommandLine makeCopy() { CommandLine cl = new CommandLine(m_startAction); // first copy the base class fields cl.m_ipcPort = m_ipcPort; cl.m_backend = m_backend; cl.m_leader = m_leader; cl.m_pathToCatalog = m_pathToCatalog; cl.m_pathToDeployment = m_pathToDeployment; cl.m_pathToLicense = m_pathToLicense; cl.m_noLoadLibVOLTDB = m_noLoadLibVOLTDB; cl.m_zkInterface = m_zkInterface; cl.m_port = m_port; cl.m_adminPort = m_adminPort; cl.m_internalPort = m_internalPort; cl.m_externalInterface = m_externalInterface; cl.m_internalInterface = m_internalInterface; cl.m_drAgentPortStart = m_drAgentPortStart; cl.m_httpPort = m_httpPort; // final in baseclass: cl.m_isEnterprise = m_isEnterprise; cl.m_deadHostTimeoutMS = m_deadHostTimeoutMS; cl.m_startMode = m_startMode; cl.m_selectedRejoinInterface = m_selectedRejoinInterface; cl.m_quietAdhoc = m_quietAdhoc; // final in baseclass: cl.m_commitLogDir = new File("/tmp"); cl.m_timestampTestingSalt = m_timestampTestingSalt; cl.m_isRejoinTest = m_isRejoinTest; cl.m_tag = m_tag; cl.m_vemTag = m_vemTag; cl.m_versionStringOverrideForTest = m_versionStringOverrideForTest; cl.m_versionCompatibilityRegexOverrideForTest = m_versionCompatibilityRegexOverrideForTest; cl.m_buildStringOverrideForTest = m_buildStringOverrideForTest; cl.m_forceVoltdbCreate = m_forceVoltdbCreate; cl.m_userSchema = m_userSchema; // second, copy the derived class fields cl.includeTestOpts = includeTestOpts; cl.debugPort = debugPort; cl.zkport = zkport; cl.buildDir = buildDir; cl.volt_root = volt_root; cl.java_library_path = java_library_path; cl.rmi_host_name = rmi_host_name; cl.log4j = log4j; cl.gcRollover = gcRollover; cl.voltFilePrefix = voltFilePrefix; cl.initialHeap = initialHeap; cl.maxHeap = maxHeap; cl.classPath = classPath; cl.javaExecutable = javaExecutable; cl.jmxPort = jmxPort; cl.jmxHost = jmxHost; cl.customCmdLn = customCmdLn; cl.m_isPaused = m_isPaused; cl.m_meshBrokers = m_meshBrokers; cl.m_coordinators = ImmutableSortedSet.copyOf(m_coordinators); cl.m_hostCount = m_hostCount; cl.m_enableAdd = m_enableAdd; cl.m_voltdbRoot = m_voltdbRoot; cl.m_newCli = m_newCli; cl.m_sslEnable = m_sslEnable; cl.m_sslExternal = m_sslExternal; cl.m_placementGroup = m_placementGroup; // deep copy the property map if it exists if (javaProperties != null) { cl.javaProperties = new TreeMap<>(); for (Entry<String, String> e : javaProperties.entrySet()) { cl.javaProperties.put(e.getKey(), e.getValue()); } } cl.m_missingHostCount = m_missingHostCount; return cl; } // PLEASE NOTE The field naming convention: VoltDB.Configuration // fields start with "m_". CommandLine fields do not have a // prefix. This helps avoid collisions given the raw number // of fields at work. In some cases, the VoltDB.Configuration // setting is set (for the m_hasLocalServer case) and a CommandLine // field is set as well (for the process builder case). boolean includeTestOpts = false; public CommandLine addTestOptions(boolean addEm) { includeTestOpts = addEm; return this; } public CommandLine port(int port) { m_port = port; return this; } public int port() { return m_port; } public int internalPort() { return m_internalPort; } public int adminPort() { return m_adminPort; } public CommandLine internalPort(int internalPort) { m_internalPort = internalPort; return this; } public CommandLine adminPort(int adminPort) { m_adminPort = adminPort; return this; } public CommandLine httpPort(int httpPort) { m_httpPort = httpPort; return this; } public CommandLine startCommand(String command) { StartAction action = StartAction.monickerFor(command); if (action == null) { // command wasn't a valid enum type, throw an exception. String msg = "Unknown action: " + command + ". "; hostLog.warn(msg); throw new IllegalArgumentException(msg); } m_startAction = action; return this; } public CommandLine startCommand(StartAction action) { m_startAction = action; return this; } public CommandLine rejoinTest(boolean rejoinTest) { m_isRejoinTest = rejoinTest; return this; } public void startPaused() { m_isPaused = true; } public CommandLine enableAdd(boolean enableAdd) { m_enableAdd = enableAdd; return this; } public CommandLine safeMode(boolean safeMode) { m_safeMode = safeMode; return this; } public boolean safeMode() { return m_safeMode; } public boolean enableAdd() { return m_enableAdd; } public CommandLine leader(String leader) { m_leader = leader; return this; } public CommandLine leaderPort(int port) { String hostname = MiscUtils.getHostnameFromHostnameColonPort(m_leader); m_leader = MiscUtils.getHostnameColonPortString(hostname, port); return this; } public CommandLine coordinators(String coordinators) { m_coordinators = MeshProber.hosts(coordinators); return this; } public CommandLine coordinators(NavigableSet<String> coordinators) { m_coordinators = coordinators; return this; } public NavigableSet<String> coordinators() { return m_coordinators; } public CommandLine timestampSalt(int timestampSalt) { m_timestampTestingSalt = timestampSalt; return this; } int debugPort = -1; public CommandLine debugPort(int debugPort) { this.debugPort = debugPort; return this; } public CommandLine ipcPort(int port) { m_ipcPort = port; return this; } int zkport = -1; public CommandLine zkport(int zkport) { this.zkport = zkport; m_zkInterface = "127.0.0.1:" + zkport; return this; } public String zkinterface() { return m_zkInterface; } String buildDir = ""; public CommandLine buildDir(String buildDir) { this.buildDir = buildDir; return this; } public String buildDir() { return buildDir; } String java_library_path = ""; public CommandLine javaLibraryPath(String javaLibraryPath) { java_library_path = javaLibraryPath; return this; } String volt_root = ""; public CommandLine voltRoot(String path) { volt_root = path; return this; } String rmi_host_name = ""; public CommandLine rmiHostName(String rmiHostName) { rmi_host_name = rmiHostName; return this; } String log4j = ""; public CommandLine log4j(String log4j) { this.log4j = log4j; return this; } boolean gcRollover = false; public CommandLine gcRollover(boolean gcRollover) { this.gcRollover = gcRollover; return this; } boolean conditionalCardMark = false; public CommandLine conditionalCardMark(boolean conditionalCardMark) { this.conditionalCardMark = conditionalCardMark; return this; } String voltFilePrefix = ""; public CommandLine voltFilePrefix(String voltFilePrefix) { if (m_newCli) return this; this.voltFilePrefix = voltFilePrefix; return this; } String initialHeap = ""; public CommandLine setInitialHeap(int megabytes) { initialHeap = "-Xms" + megabytes + "m"; return this; } String maxHeap = "-Xmx2048m"; public CommandLine setMaxHeap(int megabytes) { maxHeap = "-Xmx" + megabytes + "m"; return this; } String classPath = ""; public CommandLine classPath(String classPath) { this.classPath = classPath; return this; } public CommandLine jarFileName(String jarFileName) { m_pathToCatalog = jarFileName; return this; } public String jarFileName() { return m_pathToCatalog; } public CommandLine target(BackendTarget target) { m_backend = target; m_noLoadLibVOLTDB = (target == BackendTarget.HSQLDB_BACKEND || target == BackendTarget.POSTGRESQL_BACKEND); return this; } public BackendTarget target() { return m_backend; } public CommandLine pathToDeployment(String pathToDeployment) { m_pathToDeployment = pathToDeployment; return this; } public String pathToDeployment() { return m_pathToDeployment; } public CommandLine pathToLicense(String pathToLicense) { m_pathToLicense = pathToLicense; return this; } public String pathToLicense() { return m_pathToLicense; } public CommandLine drAgentStartPort(int portStart) { m_drAgentPortStart = portStart; return this; } public int drAgentStartPort() { return m_drAgentPortStart; } public CommandLine hostCount(int hostCount) { m_hostCount = hostCount <= 0 ? VoltDB.UNDEFINED : hostCount; return this; } public int hostCount() { return m_hostCount; } public CommandLine voltdbRoot(String voltdbRoot) { m_voltdbRoot = new VoltFile(voltdbRoot); return this; } public CommandLine voltdbRoot(File voltdbRoot) { m_voltdbRoot = voltdbRoot; return this; } public File voltdbRoot() { return m_voltdbRoot; } String javaExecutable = "java"; public CommandLine javaExecutable(String javaExecutable) { this.javaExecutable = javaExecutable; return this; } int jmxPort = 9090; public CommandLine jmxPort(int jmxPort) { this.jmxPort = jmxPort; return this; } String jmxHost = "127.0.0.1"; public CommandLine jmxHost(String jmxHost) { this.jmxHost = jmxHost; return this; } public CommandLine internalInterface(String internalInterface) { m_internalInterface = internalInterface; return this; } public CommandLine externalInterface(String externalInterface) { m_externalInterface = externalInterface; return this; } public CommandLine setForceVoltdbCreate(boolean forceVoltdbCreate) { m_forceVoltdbCreate = forceVoltdbCreate; return this; } // user-customizable string appeneded to commandline. // useful to allow customization of VEM/REST cmdlns. // Please don't abuse this by shoving lots of long-term // things here that really deserve top-level fields. String customCmdLn; public CommandLine customCmdLn(String customCmdLn) { this.customCmdLn = customCmdLn; return this; } public Map<String, String> javaProperties = null; public CommandLine setJavaProperty(String property, String value) { if (javaProperties == null) { javaProperties = new TreeMap<>(); } javaProperties.put(property, value); return this; } public String getJavaProperty(String property) { if (javaProperties == null) { return null; } return javaProperties.get(property); } public void dumpToFile(String filename) { try { FileWriter out = new FileWriter(filename); List<String> lns = createCommandLine(); for (String l : lns) { assert(l != null); out.write(l.toCharArray()); out.write('\n'); } out.flush(); out.close(); } catch (Exception e) { throw new RuntimeException(e); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); List<String> lns = createCommandLine(); for (String l : lns) { sb.append(l).append(" "); } return sb.toString(); } public void vemTag(String tag) { m_vemTag = tag; } // Return a command line list compatible with ProcessBuilder.command() public List<String> createCommandLine() { List<String> cmdline = new ArrayList<>(50); cmdline.add(javaExecutable); cmdline.add("-XX:+HeapDumpOnOutOfMemoryError"); cmdline.add("-Dsun.net.inetaddr.ttl=300"); cmdline.add("-Dsun.net.inetaddr.negative.ttl=3600"); cmdline.add("-Djava.library.path=" + java_library_path); /* * Facilitate SPNEGO (Kerberos HTTP) authentication */ cmdline.add("-Djavax.security.auth.useSubjectCredsOnly=false"); if (rmi_host_name != null) cmdline.add("-Djava.rmi.server.hostname=" + rmi_host_name); cmdline.add("-Dlog4j.configuration=" + log4j); if (m_vemTag != null) { cmdline.add("-D" + VEM_TAG_PROPERTY + "=" + m_vemTag); } if (gcRollover) { cmdline.add("-Xloggc:"+ volt_root + "/" + VEM_GC_ROLLOVER_FILE_NAME+" -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles="+VEM_GC_ROLLOVER_FILE_COUNT+" -XX:GCLogFileSize="+VEM_GC_ROLLOVER_FILE_SIZE); } cmdline.add(maxHeap); cmdline.add("-XX:+UseParNewGC"); cmdline.add("-XX:+UseConcMarkSweepGC"); cmdline.add("-XX:+CMSParallelRemarkEnabled"); cmdline.add("-XX:+UseTLAB"); cmdline.add("-XX:CMSInitiatingOccupancyFraction=75"); cmdline.add("-XX:+UseCMSInitiatingOccupancyOnly"); cmdline.add("-XX:+CMSClassUnloadingEnabled"); /* * Have RMI not invoke System.gc constantly */ cmdline.add("-Dsun.rmi.dgc.server.gcInterval=" + Long.MAX_VALUE); cmdline.add("-Dsun.rmi.dgc.client.gcInterval=" + Long.MAX_VALUE); /* * To ensure that CMS is low pause on a consistent basis, have it wait a looong time * for young gen GCs to occur when load is low. Scavenge before remark * so when remarks occur they are a consistent duration. */ cmdline.add("-XX:CMSWaitDuration=120000"); cmdline.add("-XX:CMSMaxAbortablePrecleanTime=120000"); cmdline.add("-XX:+ExplicitGCInvokesConcurrent"); cmdline.add("-XX:+CMSScavengeBeforeRemark"); //If a Volt root is provided such as local cluster or VEM, put the error file in it if ( !volt_root.isEmpty() ) { cmdline.add("-XX:ErrorFile=" + volt_root + "/hs_err_pid%p.log"); } if (conditionalCardMark) { cmdline.add("-XX:+UseCondCardMark"); } cmdline.add("-classpath"); cmdline.add(classPath); if (includeTestOpts) { cmdline.add("-DLOG_SEGMENT_SIZE=8"); if (!m_newCli) { cmdline.add("-DVoltFilePrefix=" + voltFilePrefix); } cmdline.add("-ea"); cmdline.add("-XX:MaxDirectMemorySize=2g"); } else { cmdline.add("-server"); cmdline.add("-XX:HeapDumpPath=/tmp"); if (!initialHeap.isEmpty()) { cmdline.add(initialHeap); cmdline.add("-XX:+AlwaysPreTouch"); } } if (m_isEnterprise) { cmdline.add("-Dvolt.rmi.agent.port=" + jmxPort); cmdline.add("-Dvolt.rmi.server.hostname=" + jmxHost); } // add default keystore, truststore if (m_sslEnable) { cmdline.add("-Djavax.net.ssl.keyStore=keystore"); cmdline.add("-Djavax.net.ssl.keyStorePassword=password"); cmdline.add("-Djavax.net.ssl.trustStore=keystore"); cmdline.add("-Djavax.net.ssl.trustStorePassword=password"); } if (javaProperties != null) { for (Entry<String, String> e : javaProperties.entrySet()) { if (e.getValue() != null) { cmdline.add("-D" + e.getKey() + "=" + e.getValue()); } else { cmdline.add("-D" + e.getKey()); } } } if (debugPort > -1) { cmdline.add("-Xdebug"); cmdline.add("-agentlib:jdwp=transport=dt_socket,address=" + debugPort + ",server=y,suspend=n"); } // // Process JVM options passed through the VOLTDB_OPTS environment variable // List<String> additionalJvmOptions = new ArrayList<>(); String nonJvmOptions = AdditionalJvmOptionsProcessor .getJvmOptionsFromVoltDbOptsEnvironmentVariable(additionalJvmOptions); cmdline.addAll(additionalJvmOptions); // // VOLTDB main() parameters // cmdline.add("org.voltdb.VoltDB"); cmdline.add(m_startAction.verb()); if (m_startAction == StartAction.PROBE && m_safeMode) { cmdline.add("safemode"); } if (m_startAction == StartAction.PROBE && m_enableAdd) { cmdline.add("enableadd"); } if (m_sslEnable) { cmdline.add("enableSSL"); } if (m_sslExternal) { cmdline.add("externalSSL"); } cmdline.add("host"); if (!m_coordinators.isEmpty()) { cmdline.add(Joiner.on(',').skipNulls().join(m_coordinators)); } else { cmdline.add(m_leader); } if (jarFileName() != null) { cmdline.add("catalog"); cmdline.add(jarFileName()); } //Add deployment if its not probe if (pathToDeployment() != null && m_startAction != StartAction.PROBE) { cmdline.add("deployment"); cmdline.add(pathToDeployment()); } if (includeTestOpts) { cmdline.add("timestampsalt"); cmdline.add(Long.toString(m_timestampTestingSalt)); } cmdline.add("port"); cmdline.add(Integer.toString(m_port)); cmdline.add("internalport"); cmdline.add(Integer.toString(m_internalPort)); if (m_adminPort != -1) { cmdline.add("adminport"); cmdline.add(Integer.toString(m_adminPort)); } if (zkport != -1) { cmdline.add("zkport"); cmdline.add(Integer.toString(zkport)); } if (m_drAgentPortStart != -1) { cmdline.add("replicationport"); cmdline.add(Integer.toString(m_drAgentPortStart)); } if (target() == BackendTarget.NATIVE_EE_VALGRIND_IPC) { cmdline.add("valgrind"); } if (m_internalInterface != null && !m_internalInterface.isEmpty()) { cmdline.add("internalinterface"); cmdline.add(m_internalInterface); } if (m_internalInterface != null && (m_externalInterface != null && !m_externalInterface.isEmpty())) { cmdline.add("externalinterface"); cmdline.add(m_externalInterface); } if (m_httpPort != Constants.HTTP_PORT_DISABLED) { cmdline.add("httpport"); cmdline.add(Integer.toString(m_httpPort)); } if (m_forceVoltdbCreate) { cmdline.add("force"); } if (m_isEnterprise) { cmdline.add("license"); cmdline.add(m_pathToLicense); } if (m_userSchema != null) { cmdline.add("schema"); cmdline.add(m_userSchema.getAbsolutePath()); } if (customCmdLn != null && !customCmdLn.trim().isEmpty()) { cmdline.add(customCmdLn); } // // append non JVM options from the value of the VOLTDB_OPTIONS // environment variable to customCmdLn // if( nonJvmOptions != null && !nonJvmOptions.trim().isEmpty()) { cmdline.add(nonJvmOptions); } if (m_backend.isIPC) { cmdline.add("ipcport"); cmdline.add(String.valueOf(m_ipcPort)); } if (target() == BackendTarget.NATIVE_EE_IPC) { cmdline.add("ipc"); } if (m_tag != null) { cmdline.add("tag"); cmdline.add(m_tag); } // handle overrides for testing hotfix version compatibility if (m_versionStringOverrideForTest != null) { assert(m_versionCompatibilityRegexOverrideForTest != null); cmdline.add("versionoverride"); cmdline.add(m_versionStringOverrideForTest); cmdline.add(m_versionCompatibilityRegexOverrideForTest); if (m_buildStringOverrideForTest != null) { cmdline.add("buildstringoverride"); cmdline.add(m_buildStringOverrideForTest); } } if (m_isPaused || (m_modeOverrideForTest != null && m_modeOverrideForTest.equalsIgnoreCase("paused")) ) { cmdline.add("paused"); } if (m_sitesperhost != VoltDB.UNDEFINED) { cmdline.add("sitesperhost"); cmdline.add(Integer.toString(m_sitesperhost)); } //Add mesh and hostcount for probe only. if (m_startAction == StartAction.PROBE) { cmdline.add("mesh"); cmdline.add(Joiner.on(',').skipNulls().join(m_coordinators)); cmdline.add("hostcount"); cmdline.add(Integer.toString(m_hostCount)); } if (!m_startAction.isLegacy()) { cmdline.add("voltdbroot"); cmdline.add(m_voltdbRoot.getPath()); } if (m_placementGroup != null) { cmdline.add("placementgroup"); cmdline.add(m_placementGroup); } if ( m_missingHostCount > 0) { cmdline.add("missing"); cmdline.add(Integer.toString(m_missingHostCount)); } return cmdline; } /** * <p>A utility class to parse a command line contained in a single String into * an array of argument tokens, much as the JVM (or more accurately, your * operating system) does before calling your programs' <code>public static * void main(String[] args)</code> * methods.</p> * * <p>This class has been developed to parse the command line in the same way * that MS Windows 2000 does. Arguments containing spaces should be enclosed * in quotes. Quotes that should be in the argument string should be escaped * with a preceding backslash ('\') character. Backslash characters that * should be in the argument string should also be escaped with a preceding * backslash character.</p> * * NB Adapted from J S A P implementation * */ public static class CommandLineTokenizer { /** * Hide the constructor. */ private CommandLineTokenizer() { } /** * If the specified StringBuilder is not empty, its contents are appended * to the resulting array (temporarily stored in the specified ArrayList). * The StringBuilder is then emptied in order to begin storing the next argument. * * @param resultBuffer the List temporarily storing the resulting * argument array. * @param buf the StringBuilder storing the current argument. */ private static void moveToBuffer( List<String> resultBuffer, StringBuilder buf) { if (buf.length() > 0) { resultBuffer.add(buf.toString()); buf.delete(0, buf.length()); } } /** * Parses the specified command line into an array of individual arguments. * Arguments containing spaces should be enclosed in quotes. * Quotes that should be in the argument string should be escaped with a * preceding backslash ('\') character. Backslash characters that should * be in the argument string should also be escaped with a preceding * backslash character. * @param commandLine the command line to parse * @return an argument array representing the specified command line. */ public static String[] tokenize(String commandLine) { List<String> resultBuffer = new java.util.ArrayList<>(); if (commandLine != null) { int z = commandLine.length(); Character openingQuote = null; StringBuilder buf = new StringBuilder(); for (int i = 0; i < z; ++i) { char c = commandLine.charAt(i); if (c == '"' || c == '\'') { buf.append(c); if (openingQuote == null) { openingQuote = c; } else if (openingQuote == c ) { openingQuote = null; } } else if (c == '\\') { if ((z > i + 1) && ((commandLine.charAt(i + 1) == '"') || (commandLine.charAt(i + 1) == '\\'))) { buf.append(commandLine.charAt(i + 1)); ++i; } else { buf.append("\\"); } } else { if (openingQuote != null) { buf.append(c); } else { if (Character.isWhitespace(c)) { moveToBuffer(resultBuffer, buf); } else { buf.append(c); } } } } moveToBuffer(resultBuffer, buf); } String[] result = new String[resultBuffer.size()]; return resultBuffer.toArray(result); } } /** * Processes JVM options specified in the VOLTDB_OPTIONS environment variable * * @author ssantoro * */ static class AdditionalJvmOptionsProcessor { static final String HEAP_SIZE_PREFIX = "-Xm"; static final String VOLTDB_OPTS_ENV = "VOLTDB_OPTS"; static final String VOLTDB_OPTION = "-voltdb:"; static final String DASH = "-"; /** * Options which may not be specified in VOLTDB_OPTS */ static final Set<String> mayNotSpecify = new HashSet<>( Arrays.<String>asList( "-cp", "-classpath", "-server", "-client", "-d32", "-jar", "-D" + VEM_TAG_PROPERTY, "-Djava.library.path" ) ); /** * Options that may be otherwise specified though documented * VoltDB options */ static final Set<String> mayOtherwiseSpecify = new HashSet<>( Arrays.<String>asList( "-Dlog4j.configuration", "-Xm", "-Dvolt.rmi.agent.port", "-Dvolt.rmi.server.hostname" ) ); /** * Options that have a follow up that needs to be also ignored */ static final Set<String> requiresSkipNext = new HashSet<>( Arrays.<String>asList( "-cp", "-classpath" ) ); /** * Truncate the option so that it may be looked up in * {@link $mayOtherwiseSpecify} and {@link $mayNotSpecify} * * @param option an option token * @return an optionally truncated option */ static final String truncateUptoDelimiter( String option) { if( option == null || option.trim().isEmpty()) { return null; } int delimIndex = -1; if( option.startsWith(HEAP_SIZE_PREFIX)) { delimIndex = HEAP_SIZE_PREFIX.length(); } if( delimIndex < 0) { int columnIndex = option.indexOf(":"); int equalIndex = option.indexOf("="); delimIndex = Math.min(columnIndex, equalIndex); if( delimIndex < 0) { delimIndex = Math.max(columnIndex, equalIndex); } } if( delimIndex < 0) { return option; } return option.substring(0, delimIndex); } /** * Look for jvm options and voltdb options prefixed with -V:, ignore * the ones that do conflict with VoltDB options, or the ones that * may be other wise specified through other voltDB options. * * @param jvmOptions a {@code List<String>} that is augmented with * any jvm options defined in the environment variable * @return a string containing non jvm options defined in the * environment variable */ static String getJvmOptionsFromVoltDbOptsEnvironmentVariable( final List<String> jvmOptions) { String voltDbOpts = System.getenv(VOLTDB_OPTS_ENV); if( voltDbOpts == null || voltDbOpts.trim().isEmpty()) { return null; } boolean skipNext = false; List<String> nonJvmOptions = new ArrayList<>(); for( String option: CommandLineTokenizer.tokenize(voltDbOpts)) { if( skipNext) { skipNext = false; continue; } if( option.startsWith(VOLTDB_OPTION)) { option = option.substring(VOLTDB_OPTION.length()); nonJvmOptions.add(option); continue; } if( ! option.startsWith(DASH)) { nonJvmOptions.add(option); continue; } String truncated = truncateUptoDelimiter(option); skipNext = requiresSkipNext.contains(truncated); if( mayNotSpecify.contains(truncated)) { CommandLine.hostLog.warn( "Ignoring option \"" + option + "\" as it conflicts with VoltDB JVM options" ); continue; } if( mayOtherwiseSpecify.contains(truncated)) { CommandLine.hostLog.warn( "Ignoring option \"" + option + "\" as it may be otherwise specified through VoltDB options"); continue; } jvmOptions.add(option); } boolean separate = false; StringBuilder sb = new StringBuilder(256); for( String option: nonJvmOptions) { if( separate) { sb.append( " "); } sb.append(option); separate = true; } return sb.toString(); } } boolean m_newCli = false; //Return true if we are going to run init and start. boolean isNewCli() { return m_newCli; } public void setNewCli(boolean flag) { m_newCli = flag; }; String m_placementGroup = ""; public void setPlacementGroup(String placementGroup) { m_placementGroup = placementGroup; } int m_missingHostCount = 0; public void setMissingHostCount(int missingHostCount) { this.m_missingHostCount = missingHostCount; } }