package com.ldbc.driver.control; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.ldbc.driver.Client; import com.ldbc.driver.temporal.TemporalUtil; import com.ldbc.driver.util.MapUtils; import com.ldbc.driver.workloads.ldbc.snb.interactive.LdbcSnbInteractiveWorkload; import com.ldbc.driver.workloads.ldbc.snb.interactive.db.DummyLdbcSnbInteractiveDb; import com.ldbc.driver.workloads.simple.db.SimpleDb; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import static java.lang.String.format; public class ConsoleAndFileDriverConfiguration implements DriverConfiguration { private static final TemporalUtil TEMPORAL_UTIL = new TemporalUtil(); private static final DecimalFormat INTEGRAL_FORMAT = new DecimalFormat( "###,###,###,###,###" ); private static final DecimalFormat FLOAT_FORMAT = new DecimalFormat( "###,###,###,###,##0.0000000" ); // --- REQUIRED --- public static final String OPERATION_COUNT_ARG = "oc"; public static final long OPERATION_COUNT_DEFAULT = 0; public static final String OPERATION_COUNT_DEFAULT_STRING = Long.toString( OPERATION_COUNT_DEFAULT ); private static final String OPERATION_COUNT_ARG_LONG = "operation_count"; private static final String OPERATION_COUNT_DESCRIPTION = "number of operations to execute"; public static final String WORKLOAD_ARG = "w"; private static final String WORKLOAD_ARG_LONG = "workload"; public static final String WORKLOAD_DEFAULT = null; public static final String WORKLOAD_DEFAULT_STRING = WORKLOAD_DEFAULT; private static final String WORKLOAD_EXAMPLE = com.ldbc.driver.workloads.simple.SimpleWorkload.class.getName(); private static final String WORKLOAD_DESCRIPTION = format( "class name of the Workload to use (e.g. %s)", WORKLOAD_EXAMPLE ); public static final String DB_ARG = "db"; private static final String DB_ARG_LONG = "database"; public static final String DB_DEFAULT = null; public static final String DB_DEFAULT_STRING = DB_DEFAULT; private static final String DB_EXAMPLE = SimpleDb.class.getName(); private static final String DB_DESCRIPTION = format( "class name of the DB to use (e.g. %s)", DB_EXAMPLE ); // --- OPTIONAL --- public static final String IGNORE_SCHEDULED_START_TIMES_ARG = "ignore_scheduled_start_times"; public static final boolean IGNORE_SCHEDULED_START_TIMES_DEFAULT = false; public static final String IGNORE_SCHEDULED_START_TIMES_DEFAULT_STRING = Boolean.toString( IGNORE_SCHEDULED_START_TIMES_DEFAULT ); private static final String IGNORE_SCHEDULED_START_TIMES_DESCRIPTION = "executes operations as fast as possible, ignoring their scheduled start times"; public static final String HELP_ARG = "help"; public static final boolean HELP_DEFAULT = false; public static final String HELP_DEFAULT_STRING = Boolean.toString( HELP_DEFAULT ); private static final String HELP_DESCRIPTION = "print usage instruction"; public static final String NAME_ARG = "nm"; private static final String NAME_ARG_LONG = "name"; public static final String NAME_DEFAULT = "LDBC"; public static final String NAME_DEFAULT_STRING = NAME_DEFAULT; private static final String NAME_DESCRIPTION = format( "name of the benchmark run. default = %s", NAME_DEFAULT ); public static final String RESULT_DIR_PATH_ARG = "rd"; private static final String RESULT_DIR_PATH_ARG_LONG = "results_dir"; public static final String RESULT_DIR_PATH_DEFAULT = "results"; public static final String RESULT_DIR_PATH_DEFAULT_STRING = RESULT_DIR_PATH_DEFAULT; private static final String RESULT_DIR_PATH_DESCRIPTION = format( "directory where benchmark results will be written. default = %s", RESULT_DIR_PATH_DEFAULT ); public static final String THREADS_ARG = "tc"; private static final String THREADS_ARG_LONG = "thread_count"; public static final int THREADS_DEFAULT = 1; public static final String THREADS_DEFAULT_STRING = Integer.toString( THREADS_DEFAULT ); private static final String THREADS_DESCRIPTION = format( "number of worker threads to execute with (default: %s)", THREADS_DEFAULT_STRING ); public static final String SHOW_STATUS_ARG = "s"; private static final String SHOW_STATUS_ARG_LONG = "status"; public static final int SHOW_STATUS_DEFAULT = 2; public static final String SHOW_STATUS_DEFAULT_STRING = Integer.toString( SHOW_STATUS_DEFAULT ); private static final String SHOW_STATUS_DESCRIPTION = "interval between status printouts during benchmark execution (0 = disable)"; public static final String DB_VALIDATION_FILE_PATH_ARG = "vdb"; private static final String DB_VALIDATION_FILE_PATH_ARG_LONG = "validate_database"; public static final String DB_VALIDATION_FILE_PATH_DEFAULT = null; public static final String DB_VALIDATION_FILE_PATH_DEFAULT_STRING = DB_VALIDATION_FILE_PATH_DEFAULT; private static final String DB_VALIDATION_FILE_PATH_DESCRIPTION = "path to validation parameters file, if provided database connector will be validated"; public static final String CREATE_VALIDATION_PARAMS_ARG = "cvp"; private static final String CREATE_VALIDATION_PARAMS_ARG_LONG = "create_validation_parameters"; public static final ConsoleAndFileValidationParamOptions CREATE_VALIDATION_PARAMS_DEFAULT = null; private static final String CREATE_VALIDATION_PARAMS_DESCRIPTION = "path to where validation parameters file should be created, and size of validation set to create"; public static final String CALCULATE_WORKLOAD_STATISTICS_ARG = "stats"; private static final String CALCULATE_WORKLOAD_STATISTICS_ARG_LONG = "workload_statistics"; public static final boolean CALCULATE_WORKLOAD_STATISTICS_DEFAULT = false; public static final String CALCULATE_WORKLOAD_STATISTICS_DEFAULT_STRING = Boolean.toString( CALCULATE_WORKLOAD_STATISTICS_DEFAULT ); private static final String CALCULATE_WORKLOAD_STATISTICS_DESCRIPTION = "calculate & display workload statistics (operation mix, etc.)"; public static final String TIME_UNIT_ARG = "tu"; private static final String TIME_UNIT_ARG_LONG = "time_unit"; public static final TimeUnit TIME_UNIT_DEFAULT = TimeUnit.MILLISECONDS; public static final String TIME_UNIT_DEFAULT_STRING = TIME_UNIT_DEFAULT.toString(); private static final TimeUnit[] VALID_TIME_UNITS = new TimeUnit[]{TimeUnit.NANOSECONDS, TimeUnit.MICROSECONDS, TimeUnit.MILLISECONDS, TimeUnit.SECONDS, TimeUnit.MINUTES}; private static final String TIME_UNIT_DESCRIPTION = format( "time unit to use when gathering metrics. default:%s, valid:%s", TIME_UNIT_DEFAULT_STRING, Arrays.toString( VALID_TIME_UNITS ) ); public static final String TIME_COMPRESSION_RATIO_ARG = "tcr"; private static final String TIME_COMPRESSION_RATIO_ARG_LONG = "time_compression_ratio"; public static final double TIME_COMPRESSION_RATIO_DEFAULT = 1.0; // 1.0 == do not compress public static final String TIME_COMPRESSION_RATIO_DEFAULT_STRING = Double.toString( TIME_COMPRESSION_RATIO_DEFAULT ); private static final String TIME_COMPRESSION_RATIO_DESCRIPTION = "change duration between operations of workload"; public static final String PEER_IDS_ARG = "pids"; private static final String PEER_IDS_ARG_LONG = "peer_identifiers"; public static final Set<String> PEER_IDS_DEFAULT = Sets.newHashSet(); public static final String PEER_IDS_DEFAULT_STRING = serializePeerIdsToCommandline( PEER_IDS_DEFAULT ); private static final String PEER_IDS_DESCRIPTION = "identifiers/addresses of other driver workers (for distributed mode)"; public static final String SPINNER_SLEEP_DURATION_ARG = "sw"; private static final String SPINNER_SLEEP_DURATION_ARG_LONG = "spinner_wait_duration"; public static final long SPINNER_SLEEP_DURATION_DEFAULT = 1; public static final String SPINNER_SLEEP_DURATION_DEFAULT_STRING = Long.toString( SPINNER_SLEEP_DURATION_DEFAULT ); private static final String SPINNER_SLEEP_DURATION_DESCRIPTION = "sleep duration (ms) injected into busy wait loops (to reduce CPU consumption)"; public static final String SKIP_COUNT_ARG = "sk"; private static final String SKIP_COUNT_ARG_LONG = "skip"; public static final long SKIP_COUNT_DEFAULT = 0; public static final String SKIP_COUNT_DEFAULT_STRING = Long.toString( SKIP_COUNT_DEFAULT ); private static final String SKIP_COUNT_DESCRIPTION = format( "number of operations to skip over before beginning execution (default: %s)", SKIP_COUNT_DEFAULT_STRING ); public static final String WARMUP_COUNT_ARG = "wu"; private static final String WARMUP_COUNT_ARG_LONG = "warmup"; public static final long WARMUP_COUNT_DEFAULT = 0; public static final String WARMUP_COUNT_DEFAULT_STRING = Long.toString( WARMUP_COUNT_DEFAULT ); private static final String WARMUP_COUNT_DESCRIPTION = format( "number of operations to execute during warmup phase (default: %s)", WARMUP_COUNT_DEFAULT_STRING ); public static final String PROPERTY_FILE_ARG = "P"; private static final String PROPERTY_FILE_DESCRIPTION = "load properties from file(s) - files will be loaded in the order provided\n" + "first files are highest priority; later values will not override earlier values"; public static final String PROPERTY_ARG = "p"; private static final String PROPERTY_DESCRIPTION = "properties to be passed to DB and Workload - these will override properties loaded from files"; private static final Options OPTIONS = buildOptions(); private static final char COMMANDLINE_SEPARATOR_CHAR = '|'; private static final String COMMANDLINE_SEPARATOR_REGEX_STRING = "\\|"; public static Map<String,String> defaultsAsMap() throws DriverConfigurationException { Map<String,String> defaultParamsMap = new HashMap<>(); defaultParamsMap.put( IGNORE_SCHEDULED_START_TIMES_ARG, IGNORE_SCHEDULED_START_TIMES_DEFAULT_STRING ); defaultParamsMap.put( HELP_ARG, HELP_DEFAULT_STRING ); defaultParamsMap.put( OPERATION_COUNT_ARG, OPERATION_COUNT_DEFAULT_STRING ); defaultParamsMap.put( WORKLOAD_ARG, WORKLOAD_DEFAULT_STRING ); defaultParamsMap.put( NAME_ARG, NAME_DEFAULT_STRING ); defaultParamsMap.put( DB_ARG, DB_DEFAULT_STRING ); defaultParamsMap.put( RESULT_DIR_PATH_ARG, RESULT_DIR_PATH_DEFAULT_STRING ); defaultParamsMap.put( THREADS_ARG, THREADS_DEFAULT_STRING ); defaultParamsMap.put( SHOW_STATUS_ARG, SHOW_STATUS_DEFAULT_STRING ); if ( null != DB_VALIDATION_FILE_PATH_DEFAULT_STRING ) { defaultParamsMap.put( DB_VALIDATION_FILE_PATH_ARG, DB_VALIDATION_FILE_PATH_DEFAULT_STRING ); } if ( null != CREATE_VALIDATION_PARAMS_DEFAULT ) { defaultParamsMap .put( CREATE_VALIDATION_PARAMS_ARG, CREATE_VALIDATION_PARAMS_DEFAULT.toCommandlineString() ); } defaultParamsMap.put( CALCULATE_WORKLOAD_STATISTICS_ARG, CALCULATE_WORKLOAD_STATISTICS_DEFAULT_STRING ); defaultParamsMap.put( TIME_UNIT_ARG, TIME_UNIT_DEFAULT_STRING ); defaultParamsMap.put( TIME_COMPRESSION_RATIO_ARG, TIME_COMPRESSION_RATIO_DEFAULT_STRING ); defaultParamsMap.put( PEER_IDS_ARG, PEER_IDS_DEFAULT_STRING ); defaultParamsMap.put( SPINNER_SLEEP_DURATION_ARG, SPINNER_SLEEP_DURATION_DEFAULT_STRING ); defaultParamsMap.put( WARMUP_COUNT_ARG, WARMUP_COUNT_DEFAULT_STRING ); defaultParamsMap.put( SKIP_COUNT_ARG, SKIP_COUNT_DEFAULT_STRING ); return defaultParamsMap; } public static ConsoleAndFileDriverConfiguration fromArgs( String[] args ) throws DriverConfigurationException { try { Map<String,String> paramsMap = parseArgs( args, OPTIONS ); return fromParamsMap( paramsMap ); } catch ( Exception e ) { throw new DriverConfigurationException( format( "%s\n%s", e.getMessage(), commandlineHelpString() ), e ); } } public static ConsoleAndFileDriverConfiguration fromDefaults( String databaseClassName, String workloadClassName, long operationCount ) throws DriverConfigurationException { try { Map<String,String> paramsMap = defaultsAsMap(); paramsMap.put( DB_ARG, databaseClassName ); paramsMap.put( WORKLOAD_ARG, workloadClassName ); paramsMap.put( OPERATION_COUNT_ARG, Long.toString( operationCount ) ); return fromParamsMap( paramsMap ); } catch ( DriverConfigurationException e ) { throw new DriverConfigurationException( format( "%s\n%s", e.getMessage(), commandlineHelpString() ), e ); } } public static ConsoleAndFileDriverConfiguration fromParamsMap( Map<String,String> paramsMap ) throws DriverConfigurationException { try { paramsMap = convertLongKeysToShortKeys( paramsMap ); if ( paramsMap.containsKey( TIME_UNIT_ARG ) ) { assertValidTimeUnit( paramsMap.get( TIME_UNIT_ARG ) ); } paramsMap = MapUtils.mergeMaps( paramsMap, defaultsAsMap(), false ); String name = paramsMap.get( NAME_ARG ); String dbClassName = paramsMap.get( DB_ARG ); String workloadClassName = paramsMap.get( WORKLOAD_ARG ); long operationCount = Long.parseLong( paramsMap.get( OPERATION_COUNT_ARG ) ); int threadCount = Integer.parseInt( paramsMap.get( THREADS_ARG ) ); int statusDisplayIntervalAsSeconds = Integer.parseInt( paramsMap.get( SHOW_STATUS_ARG ) ); TimeUnit timeUnit = TimeUnit.valueOf( paramsMap.get( TIME_UNIT_ARG ) ); String resultDirPath = paramsMap.get( RESULT_DIR_PATH_ARG ); double timeCompressionRatio = Double.parseDouble( paramsMap.get( TIME_COMPRESSION_RATIO_ARG ) ); Set<String> peerIds = parsePeerIdsFromCommandline( paramsMap.get( PEER_IDS_ARG ) ); ConsoleAndFileValidationParamOptions databaseConsoleAndFileValidationParams = (null == paramsMap.get( CREATE_VALIDATION_PARAMS_ARG )) ? null : ConsoleAndFileValidationParamOptions .fromCommandlineString( paramsMap.get( CREATE_VALIDATION_PARAMS_ARG ) ); String databaseValidationFilePath = paramsMap.get( DB_VALIDATION_FILE_PATH_ARG ); boolean calculateWorkloadStatistics = Boolean.parseBoolean( paramsMap.get( CALCULATE_WORKLOAD_STATISTICS_ARG ) ); long spinnerSleepDurationAsMilli = Long.parseLong( paramsMap.get( SPINNER_SLEEP_DURATION_ARG ) ); long skipCount = Long.parseLong( paramsMap.get( SKIP_COUNT_ARG ) ); long warmupCount = Long.parseLong( paramsMap.get( WARMUP_COUNT_ARG ) ); boolean printHelp = Boolean.parseBoolean( paramsMap.get( HELP_ARG ) ); boolean ignoreScheduledStartTimes = Boolean.parseBoolean( paramsMap.get( IGNORE_SCHEDULED_START_TIMES_ARG ) ); return new ConsoleAndFileDriverConfiguration( paramsMap, name, dbClassName, workloadClassName, operationCount, threadCount, statusDisplayIntervalAsSeconds, timeUnit, resultDirPath, timeCompressionRatio, peerIds, databaseConsoleAndFileValidationParams, databaseValidationFilePath, calculateWorkloadStatistics, spinnerSleepDurationAsMilli, printHelp, ignoreScheduledStartTimes, warmupCount, skipCount ); } catch ( DriverConfigurationException e ) { throw new DriverConfigurationException( format( "%s\n%s", e.getMessage(), commandlineHelpString() ), e ); } } private static void assertValidTimeUnit( String timeUnitString ) throws DriverConfigurationException { try { TimeUnit timeUnit = TimeUnit.valueOf( timeUnitString ); Set<TimeUnit> validTimeUnits = new HashSet<>(); validTimeUnits.addAll( Arrays.asList( VALID_TIME_UNITS ) ); if ( !validTimeUnits.contains( timeUnit ) ) { throw new IllegalArgumentException(); } } catch ( IllegalArgumentException e ) { throw new DriverConfigurationException( format( "Unsupported TimeUnit value: %s", timeUnitString ) ); } } private static Map<String,String> parseArgs( String[] args, Options options ) throws ParseException, DriverConfigurationException { Map<String,String> cmdParams = new HashMap<>(); Map<String,String> fileParams = new HashMap<>(); CommandLineParser parser = new BasicParser(); CommandLine cmd = parser.parse( options, args ); /* * Required */ if ( cmd.hasOption( DB_ARG ) ) { cmdParams.put( DB_ARG, cmd.getOptionValue( DB_ARG ) ); } if ( cmd.hasOption( WORKLOAD_ARG ) ) { cmdParams.put( WORKLOAD_ARG, cmd.getOptionValue( WORKLOAD_ARG ) ); } if ( cmd.hasOption( OPERATION_COUNT_ARG ) ) { cmdParams.put( OPERATION_COUNT_ARG, cmd.getOptionValue( OPERATION_COUNT_ARG ) ); } /* * Optional */ if ( cmd.hasOption( NAME_ARG ) ) { cmdParams.put( NAME_ARG, cmd.getOptionValue( NAME_ARG ) ); } if ( cmd.hasOption( RESULT_DIR_PATH_ARG ) ) { cmdParams.put( RESULT_DIR_PATH_ARG, cmd.getOptionValue( RESULT_DIR_PATH_ARG ) ); } if ( cmd.hasOption( THREADS_ARG ) ) { cmdParams.put( THREADS_ARG, cmd.getOptionValue( THREADS_ARG ) ); } if ( cmd.hasOption( SHOW_STATUS_ARG ) ) { cmdParams.put( SHOW_STATUS_ARG, cmd.getOptionValue( SHOW_STATUS_ARG ) ); } if ( cmd.hasOption( TIME_UNIT_ARG ) ) { cmdParams.put( TIME_UNIT_ARG, cmd.getOptionValue( TIME_UNIT_ARG ) ); } if ( cmd.hasOption( TIME_COMPRESSION_RATIO_ARG ) ) { cmdParams.put( TIME_COMPRESSION_RATIO_ARG, cmd.getOptionValue( TIME_COMPRESSION_RATIO_ARG ) ); } if ( cmd.hasOption( CREATE_VALIDATION_PARAMS_ARG ) ) { cmdParams.put( CREATE_VALIDATION_PARAMS_ARG, cmd.getOptionValue( CREATE_VALIDATION_PARAMS_ARG ) ); } if ( cmd.hasOption( DB_VALIDATION_FILE_PATH_ARG ) ) { cmdParams.put( DB_VALIDATION_FILE_PATH_ARG, cmd.getOptionValue( DB_VALIDATION_FILE_PATH_ARG ) ); } if ( cmd.hasOption( CALCULATE_WORKLOAD_STATISTICS_ARG ) ) { cmdParams.put( CALCULATE_WORKLOAD_STATISTICS_ARG, Boolean.toString( true ) ); } if ( cmd.hasOption( SPINNER_SLEEP_DURATION_ARG ) ) { cmdParams.put( SPINNER_SLEEP_DURATION_ARG, cmd.getOptionValue( SPINNER_SLEEP_DURATION_ARG ) ); } if ( cmd.hasOption( CREATE_VALIDATION_PARAMS_ARG ) ) { cmdParams.put( CREATE_VALIDATION_PARAMS_ARG, cmd.getOptionValue( CREATE_VALIDATION_PARAMS_ARG ) ); } if ( cmd.hasOption( HELP_ARG ) ) { cmdParams.put( HELP_ARG, Boolean.toString( true ) ); } if ( cmd.hasOption( IGNORE_SCHEDULED_START_TIMES_ARG ) ) { cmdParams.put( IGNORE_SCHEDULED_START_TIMES_ARG, Boolean.toString( true ) ); } if ( cmd.hasOption( WARMUP_COUNT_ARG ) ) { cmdParams.put( WARMUP_COUNT_ARG, cmd.getOptionValue( WARMUP_COUNT_ARG ) ); } if ( cmd.hasOption( SKIP_COUNT_ARG ) ) { cmdParams.put( SKIP_COUNT_ARG, cmd.getOptionValue( SKIP_COUNT_ARG ) ); } if ( cmd.hasOption( CREATE_VALIDATION_PARAMS_ARG ) ) { String[] validationParams = cmd.getOptionValues( CREATE_VALIDATION_PARAMS_ARG ); String filePath = validationParams[0]; int validationSetSize = Integer.parseInt( validationParams[1] ); cmdParams.put( CREATE_VALIDATION_PARAMS_ARG, new ConsoleAndFileValidationParamOptions( filePath, validationSetSize ).toCommandlineString() ); } if ( cmd.hasOption( PEER_IDS_ARG ) ) { Set<String> peerIds = new HashSet<>(); Collections.addAll( peerIds, cmd.getOptionValues( PEER_IDS_ARG ) ); cmdParams.put( PEER_IDS_ARG, serializePeerIdsToCommandline( peerIds ) ); } if ( cmd.hasOption( PROPERTY_FILE_ARG ) ) { for ( String propertyFilePath : cmd.getOptionValues( PROPERTY_FILE_ARG ) ) { // code assumes ordering -> first files more important than last, first values get priority try { Properties tempFileProperties = new Properties(); tempFileProperties.load( new FileInputStream( propertyFilePath ) ); Map<String,String> tempFileParams = MapUtils.propertiesToMap( tempFileProperties ); boolean overwrite = true; fileParams = MapUtils.mergeMaps( convertLongKeysToShortKeys( tempFileParams ), fileParams, overwrite ); } catch ( IOException e ) { throw new ParseException( format( "Error loading properties file %s\n%s", propertyFilePath, e.getMessage() ) ); } } } if ( cmd.hasOption( PROPERTY_ARG ) ) { for ( Entry<Object,Object> cmdProperty : cmd.getOptionProperties( PROPERTY_ARG ).entrySet() ) { cmdParams.put( (String) cmdProperty.getKey(), (String) cmdProperty.getValue() ); } } boolean overwrite = true; return MapUtils.mergeMaps( convertLongKeysToShortKeys( fileParams ), convertLongKeysToShortKeys( cmdParams ), overwrite ); } public static Map<String,String> convertLongKeysToShortKeys( Map<String,String> paramsMap ) { paramsMap = replaceKey( paramsMap, OPERATION_COUNT_ARG_LONG, OPERATION_COUNT_ARG ); paramsMap = replaceKey( paramsMap, NAME_ARG_LONG, NAME_ARG ); paramsMap = replaceKey( paramsMap, WORKLOAD_ARG_LONG, WORKLOAD_ARG ); paramsMap = replaceKey( paramsMap, DB_ARG_LONG, DB_ARG ); paramsMap = replaceKey( paramsMap, THREADS_ARG_LONG, THREADS_ARG ); paramsMap = replaceKey( paramsMap, SHOW_STATUS_ARG_LONG, SHOW_STATUS_ARG ); paramsMap = replaceKey( paramsMap, TIME_UNIT_ARG_LONG, TIME_UNIT_ARG ); paramsMap = replaceKey( paramsMap, RESULT_DIR_PATH_ARG_LONG, RESULT_DIR_PATH_ARG ); paramsMap = replaceKey( paramsMap, TIME_COMPRESSION_RATIO_ARG_LONG, TIME_COMPRESSION_RATIO_ARG ); paramsMap = replaceKey( paramsMap, PEER_IDS_ARG_LONG, PEER_IDS_ARG ); paramsMap = replaceKey( paramsMap, CREATE_VALIDATION_PARAMS_ARG_LONG, CREATE_VALIDATION_PARAMS_ARG ); paramsMap = replaceKey( paramsMap, DB_VALIDATION_FILE_PATH_ARG_LONG, DB_VALIDATION_FILE_PATH_ARG ); paramsMap = replaceKey( paramsMap, CALCULATE_WORKLOAD_STATISTICS_ARG_LONG, CALCULATE_WORKLOAD_STATISTICS_ARG ); paramsMap = replaceKey( paramsMap, SPINNER_SLEEP_DURATION_ARG_LONG, SPINNER_SLEEP_DURATION_ARG ); paramsMap = replaceKey( paramsMap, WARMUP_COUNT_ARG_LONG, WARMUP_COUNT_ARG ); paramsMap = replaceKey( paramsMap, SKIP_COUNT_ARG_LONG, SKIP_COUNT_ARG ); return paramsMap; } // NOTE: not safe in general case, no check for duplicate keys, i.e., if newKey already exists its value will be // overwritten private static Map<String,String> replaceKey( Map<String,String> paramsMap, String oldKey, String newKey ) { if ( false == paramsMap.containsKey( oldKey ) ) { return paramsMap; } String value = paramsMap.get( oldKey ); paramsMap.remove( oldKey ); paramsMap.put( newKey, value ); return paramsMap; } private static Options buildOptions() { Options options = new Options(); /* * Required */ Option dbOption = OptionBuilder.hasArgs( 1 ).withArgName( "classname" ).withDescription( DB_DESCRIPTION ).withLongOpt( DB_ARG_LONG ).create( DB_ARG ); options.addOption( dbOption ); Option workloadOption = OptionBuilder.hasArgs( 1 ).withArgName( "classname" ).withDescription( WORKLOAD_DESCRIPTION ).withLongOpt( WORKLOAD_ARG_LONG ).create( WORKLOAD_ARG ); options.addOption( workloadOption ); Option operationCountOption = OptionBuilder.hasArgs( 1 ).withArgName( "count" ).withDescription( OPERATION_COUNT_DESCRIPTION ).withLongOpt( OPERATION_COUNT_ARG_LONG ).create( OPERATION_COUNT_ARG ); options.addOption( operationCountOption ); /* * Optional */ Option nameOption = OptionBuilder.hasArgs( 1 ).withArgName( "name" ).withDescription( NAME_DESCRIPTION ).withLongOpt( NAME_ARG_LONG ).create( NAME_ARG ); options.addOption( nameOption ); Option resultFileOption = OptionBuilder.hasArgs( 1 ).withArgName( "path" ).withDescription( RESULT_DIR_PATH_DESCRIPTION ) .withLongOpt( RESULT_DIR_PATH_ARG_LONG ).create( RESULT_DIR_PATH_ARG ); options.addOption( resultFileOption ); Option threadsOption = OptionBuilder.hasArgs( 1 ).withArgName( "count" ).withDescription( THREADS_DESCRIPTION ).withLongOpt( THREADS_ARG_LONG ).create( THREADS_ARG ); options.addOption( threadsOption ); Option statusOption = OptionBuilder.hasArgs( 1 ).withArgName( "seconds" ).withDescription( SHOW_STATUS_DESCRIPTION ) .withLongOpt( SHOW_STATUS_ARG_LONG ).create( SHOW_STATUS_ARG ); options.addOption( statusOption ); Option timeUnitOption = OptionBuilder.hasArgs( 1 ).withArgName( "unit" ).withDescription( TIME_UNIT_DESCRIPTION ).withLongOpt( TIME_UNIT_ARG_LONG ).create( TIME_UNIT_ARG ); options.addOption( timeUnitOption ); Option timeCompressionRatioOption = OptionBuilder.hasArgs( 1 ).withArgName( "ratio" ).withDescription( TIME_COMPRESSION_RATIO_DESCRIPTION ) .withLongOpt( TIME_COMPRESSION_RATIO_ARG_LONG ).create( TIME_COMPRESSION_RATIO_ARG ); options.addOption( timeCompressionRatioOption ); Option peerIdsOption = OptionBuilder.hasArgs().withValueSeparator( COMMANDLINE_SEPARATOR_CHAR ) .withArgName( "peerId1" + COMMANDLINE_SEPARATOR_CHAR + "peerId2" ).withDescription( PEER_IDS_DESCRIPTION ).withLongOpt( PEER_IDS_ARG_LONG ).create( PEER_IDS_ARG ); options.addOption( peerIdsOption ); Option dbValidationParamsOption = OptionBuilder.hasArgs( 2 ).withValueSeparator( COMMANDLINE_SEPARATOR_CHAR ) .withArgName( "path" + COMMANDLINE_SEPARATOR_CHAR + "count" ) .withDescription( CREATE_VALIDATION_PARAMS_DESCRIPTION ).withLongOpt( CREATE_VALIDATION_PARAMS_ARG_LONG ).create( CREATE_VALIDATION_PARAMS_ARG ); options.addOption( dbValidationParamsOption ); Option databaseValidationFilePathOption = OptionBuilder.hasArgs( 1 ).withArgName( "path" ).withDescription( DB_VALIDATION_FILE_PATH_DESCRIPTION ) .withLongOpt( DB_VALIDATION_FILE_PATH_ARG_LONG ).create( DB_VALIDATION_FILE_PATH_ARG ); options.addOption( databaseValidationFilePathOption ); Option calculateWorkloadStatisticsOption = OptionBuilder.withDescription( CALCULATE_WORKLOAD_STATISTICS_DESCRIPTION ).withLongOpt( CALCULATE_WORKLOAD_STATISTICS_ARG_LONG ).create( CALCULATE_WORKLOAD_STATISTICS_ARG ); options.addOption( calculateWorkloadStatisticsOption ); Option spinnerSleepDurationOption = OptionBuilder.hasArgs( 1 ).withArgName( "duration" ) .withDescription( SPINNER_SLEEP_DURATION_DESCRIPTION ).withLongOpt( SPINNER_SLEEP_DURATION_ARG_LONG ).create( SPINNER_SLEEP_DURATION_ARG ); options.addOption( spinnerSleepDurationOption ); Option warmupCountOption = OptionBuilder.hasArgs( 1 ).withArgName( "count" ).withDescription( WARMUP_COUNT_DESCRIPTION ) .withLongOpt( WARMUP_COUNT_ARG_LONG ).create( WARMUP_COUNT_ARG ); options.addOption( warmupCountOption ); Option skipCountOption = OptionBuilder.hasArgs( 1 ).withArgName( "count" ).withDescription( SKIP_COUNT_DESCRIPTION ) .withLongOpt( SKIP_COUNT_ARG_LONG ).create( SKIP_COUNT_ARG ); options.addOption( skipCountOption ); Option printHelpOption = OptionBuilder.withDescription( HELP_DESCRIPTION ).create( HELP_ARG ); options.addOption( printHelpOption ); Option ignoreScheduledStartTimesOption = OptionBuilder.withDescription( IGNORE_SCHEDULED_START_TIMES_DESCRIPTION ) .create( IGNORE_SCHEDULED_START_TIMES_ARG ); options.addOption( ignoreScheduledStartTimesOption ); Option propertyFileOption = OptionBuilder.hasArgs().withValueSeparator( COMMANDLINE_SEPARATOR_CHAR ) .withArgName( "file1" + COMMANDLINE_SEPARATOR_CHAR + "file2" ).withDescription( PROPERTY_FILE_DESCRIPTION ).create( PROPERTY_FILE_ARG ); options.addOption( propertyFileOption ); Option propertyOption = OptionBuilder.hasArgs( 2 ).withValueSeparator( COMMANDLINE_SEPARATOR_CHAR ) .withArgName( "key" + COMMANDLINE_SEPARATOR_CHAR + "value" ).withDescription( PROPERTY_DESCRIPTION ).create( PROPERTY_ARG ); options.addOption( propertyOption ); return options; } static Set<String> parsePeerIdsFromCommandline( String peerIdsString ) { Set<String> peerIds = new HashSet<>(); String[] peerIdsArray = peerIdsString.split( COMMANDLINE_SEPARATOR_REGEX_STRING ); for ( String peerId : peerIdsArray ) { if ( !peerId.isEmpty() ) { peerIds.add( peerId ); } } return peerIds; } static String serializePeerIdsToCommandline( Set<String> peerIds ) { List<String> peerIdsList = Lists.newArrayList( peerIds ); if ( 0 == peerIdsList.size() ) { return ""; } if ( 1 == peerIdsList.size() ) { return peerIdsList.get( 0 ); } String commandLinePeerIdsString = ""; for ( int i = 0; i < peerIdsList.size() - 1; i++ ) { commandLinePeerIdsString += peerIdsList.get( i ) + COMMANDLINE_SEPARATOR_CHAR; } commandLinePeerIdsString += peerIdsList.get( peerIds.size() - 1 ); return commandLinePeerIdsString; } private static Set<String> coreConfigurationParameterKeys() { return Sets.newHashSet( NAME_ARG, DB_ARG, WORKLOAD_ARG, OPERATION_COUNT_ARG, THREADS_ARG, SHOW_STATUS_ARG, TIME_UNIT_ARG, RESULT_DIR_PATH_ARG, TIME_COMPRESSION_RATIO_ARG, PEER_IDS_ARG, CREATE_VALIDATION_PARAMS_ARG, DB_VALIDATION_FILE_PATH_ARG, CALCULATE_WORKLOAD_STATISTICS_ARG, SPINNER_SLEEP_DURATION_ARG, HELP_ARG, IGNORE_SCHEDULED_START_TIMES_ARG, WARMUP_COUNT_ARG, SKIP_COUNT_ARG ); } public static String commandlineHelpString() { Options options = OPTIONS; int printedRowWidth = 110; String header = ""; String footer = ""; int spacesBeforeOption = 3; int spacesBeforeOptionDescription = 5; boolean displayUsage = true; String commandLineSyntax = "java -cp jeeves-VERSION.jar " + Client.class.getName(); ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintWriter writer = new PrintWriter( os ); HelpFormatter helpFormatter = new HelpFormatter(); helpFormatter.printHelp( writer, printedRowWidth, commandLineSyntax, header, options, spacesBeforeOption, spacesBeforeOptionDescription, footer, displayUsage ); writer.flush(); writer.close(); return os.toString(); } private final Map<String,String> paramsMap; private final String name; private final String dbClassName; private final String workloadClassName; private final long operationCount; private final int threadCount; private final int statusDisplayIntervalAsSeconds; private final TimeUnit timeUnit; private final String resultDirPath; private final double timeCompressionRatio; private final Set<String> peerIds; private final ConsoleAndFileValidationParamOptions validationCreationParams; private final String databaseValidationFilePath; private final boolean calculateWorkloadStatistics; private final long spinnerSleepDurationAsMilli; private final boolean printHelp; private final boolean ignoreScheduledStartTimes; private final long warmupCount; private final long skipCount; public ConsoleAndFileDriverConfiguration( Map<String,String> paramsMap, String name, String dbClassName, String workloadClassName, long operationCount, int threadCount, int statusDisplayIntervalAsSeconds, TimeUnit timeUnit, String resultDirPath, double timeCompressionRatio, Set<String> peerIds, ConsoleAndFileValidationParamOptions validationCreationParams, String databaseValidationFilePath, boolean calculateWorkloadStatistics, long spinnerSleepDurationAsMilli, boolean printHelp, boolean ignoreScheduledStartTimes, long warmupCount, long skipCount ) { if ( null == paramsMap ) { paramsMap = new HashMap<>(); } this.paramsMap = paramsMap; this.name = name; this.dbClassName = dbClassName; this.workloadClassName = workloadClassName; this.operationCount = operationCount; this.threadCount = threadCount; this.statusDisplayIntervalAsSeconds = statusDisplayIntervalAsSeconds; this.timeUnit = timeUnit; this.resultDirPath = resultDirPath; this.timeCompressionRatio = timeCompressionRatio; this.peerIds = peerIds; this.validationCreationParams = validationCreationParams; this.databaseValidationFilePath = databaseValidationFilePath; this.calculateWorkloadStatistics = calculateWorkloadStatistics; this.spinnerSleepDurationAsMilli = spinnerSleepDurationAsMilli; this.printHelp = printHelp; this.ignoreScheduledStartTimes = ignoreScheduledStartTimes; this.warmupCount = warmupCount; this.skipCount = skipCount; if ( null != name ) { paramsMap.put( NAME_ARG, name ); } if ( null != dbClassName ) { paramsMap.put( DB_ARG, dbClassName ); } paramsMap.put( OPERATION_COUNT_ARG, Long.toString( operationCount ) ); if ( null != workloadClassName ) { paramsMap.put( WORKLOAD_ARG, workloadClassName ); } paramsMap.put( THREADS_ARG, Integer.toString( threadCount ) ); paramsMap.put( SHOW_STATUS_ARG, Integer.toString( statusDisplayIntervalAsSeconds ) ); paramsMap.put( TIME_UNIT_ARG, timeUnit.name() ); if ( null != resultDirPath ) { paramsMap.put( RESULT_DIR_PATH_ARG, resultDirPath ); } paramsMap.put( TIME_COMPRESSION_RATIO_ARG, Double.toString( timeCompressionRatio ) ); paramsMap.put( PEER_IDS_ARG, serializePeerIdsToCommandline( peerIds ) ); if ( null != validationCreationParams ) { paramsMap.put( CREATE_VALIDATION_PARAMS_ARG, validationCreationParams.toCommandlineString() ); } if ( null != databaseValidationFilePath ) { paramsMap.put( DB_VALIDATION_FILE_PATH_ARG, databaseValidationFilePath ); } paramsMap.put( CALCULATE_WORKLOAD_STATISTICS_ARG, Boolean.toString( calculateWorkloadStatistics ) ); paramsMap.put( SPINNER_SLEEP_DURATION_ARG, Long.toString( spinnerSleepDurationAsMilli ) ); paramsMap.put( HELP_ARG, Boolean.toString( printHelp ) ); paramsMap.put( IGNORE_SCHEDULED_START_TIMES_ARG, Boolean.toString( ignoreScheduledStartTimes ) ); paramsMap.put( WARMUP_COUNT_ARG, Long.toString( warmupCount ) ); paramsMap.put( SKIP_COUNT_ARG, Long.toString( skipCount ) ); } @Override public String name() { return name; } @Override public String dbClassName() { return dbClassName; } @Override public String workloadClassName() { return workloadClassName; } @Override public long operationCount() { return operationCount; } @Override public int threadCount() { return threadCount; } @Override public int statusDisplayIntervalAsSeconds() { return statusDisplayIntervalAsSeconds; } @Override public TimeUnit timeUnit() { return timeUnit; } @Override public String resultDirPath() { if ( null == resultDirPath ) { return null; } else { return new File( resultDirPath ).getAbsolutePath(); } } @Override public double timeCompressionRatio() { return timeCompressionRatio; } @Override public Set<String> peerIds() { return peerIds; } @Override public ValidationParamOptions validationParamsCreationOptions() { return validationCreationParams; } @Override public String databaseValidationFilePath() { return databaseValidationFilePath; } @Override public boolean calculateWorkloadStatistics() { return calculateWorkloadStatistics; } @Override public long spinnerSleepDurationAsMilli() { return spinnerSleepDurationAsMilli; } @Override public boolean shouldPrintHelpString() { return printHelp; } @Override public String helpString() { return ConsoleAndFileDriverConfiguration.commandlineHelpString(); } @Override public boolean ignoreScheduledStartTimes() { return ignoreScheduledStartTimes; } @Override public long warmupCount() { return warmupCount; } @Override public long skipCount() { return skipCount; } @Override public Map<String,String> asMap() { return paramsMap; } /** * Returns a new DriverConfiguration instance. * New instance has the same values for all fields except those that have an associated value in the new config. * New instance contains all fields that original configuration instance contained. * New instance will contain additional fields if new config introduced any. * * @param newConfiguration * @return * @throws DriverConfigurationException */ @Override public DriverConfiguration applyArgs( DriverConfiguration newConfiguration ) throws DriverConfigurationException { return applyArgs( newConfiguration.asMap() ); } /** * Returns a new DriverConfiguration instance. * New instance has the same values for all fields except the one that was set/changed. * New instance contains all fields that original configuration instance contained. * New instance will contain additional fields if the new parameter introduced one. * * @param argument * @param newValue * @return * @throws DriverConfigurationException */ public DriverConfiguration applyArg( String argument, String newValue ) throws DriverConfigurationException { Map<String,String> newParamsMap = new HashMap<>(); newParamsMap.put( argument, newValue ); return applyArgs( newParamsMap ); } /** * Returns a new DriverConfiguration instance. * New instance has the same values for all fields except those that have an associated value in the new parameters * map. * New instance contains all fields that original configuration instance contained. * New instance will contain additional fields if new parameters map introduced any. * * @param newParamsMap * @return * @throws DriverConfigurationException */ @Override public DriverConfiguration applyArgs( Map<String,String> newParamsMap ) throws DriverConfigurationException { Map<String,String> newParamsMapWithShortKeys = convertLongKeysToShortKeys( newParamsMap ); Map<String,String> newOtherParams = MapUtils.mergeMaps( this.paramsMap, newParamsMapWithShortKeys, true ); String newName = (newParamsMapWithShortKeys.containsKey( NAME_ARG )) ? newParamsMapWithShortKeys.get( NAME_ARG ) : name; String newDbClassName = (newParamsMapWithShortKeys.containsKey( DB_ARG )) ? newParamsMapWithShortKeys.get( DB_ARG ) : dbClassName; String newWorkloadClassName = (newParamsMapWithShortKeys.containsKey( WORKLOAD_ARG )) ? newParamsMapWithShortKeys.get( WORKLOAD_ARG ) : workloadClassName; long newOperationCount = (newParamsMapWithShortKeys.containsKey( OPERATION_COUNT_ARG )) ? Long.parseLong( newParamsMapWithShortKeys.get( OPERATION_COUNT_ARG ) ) : operationCount; int newThreadCount = (newParamsMapWithShortKeys.containsKey( THREADS_ARG )) ? Integer.parseInt( newParamsMapWithShortKeys.get( THREADS_ARG ) ) : threadCount; int newStatusDisplayIntervalAsSeconds = (newParamsMapWithShortKeys.containsKey( SHOW_STATUS_ARG )) ? Integer.parseInt( newParamsMapWithShortKeys.get( SHOW_STATUS_ARG ) ) : statusDisplayIntervalAsSeconds; TimeUnit newTimeUnit = (newParamsMapWithShortKeys.containsKey( TIME_UNIT_ARG )) ? TimeUnit.valueOf( newParamsMapWithShortKeys.get( TIME_UNIT_ARG ) ) : timeUnit; String newResultDirPath = (newParamsMapWithShortKeys.containsKey( RESULT_DIR_PATH_ARG )) ? newParamsMapWithShortKeys.get( RESULT_DIR_PATH_ARG ) : resultDirPath; double newTimeCompressionRatio = (newParamsMapWithShortKeys.containsKey( TIME_COMPRESSION_RATIO_ARG )) ? Double.parseDouble( newParamsMapWithShortKeys.get( TIME_COMPRESSION_RATIO_ARG ) ) : timeCompressionRatio; Set<String> newPeerIds = (newParamsMapWithShortKeys.containsKey( PEER_IDS_ARG )) ? parsePeerIdsFromCommandline( newParamsMapWithShortKeys.get( PEER_IDS_ARG ) ) : peerIds; ConsoleAndFileValidationParamOptions newValidationParams = (newParamsMapWithShortKeys.containsKey( CREATE_VALIDATION_PARAMS_ARG )) ? (null == newParamsMapWithShortKeys.get( CREATE_VALIDATION_PARAMS_ARG )) ? null : ConsoleAndFileValidationParamOptions .fromCommandlineString( newParamsMapWithShortKeys.get( CREATE_VALIDATION_PARAMS_ARG ) ) : validationCreationParams; String newDatabaseValidationFilePath = (newParamsMapWithShortKeys.containsKey( DB_VALIDATION_FILE_PATH_ARG )) ? newParamsMapWithShortKeys.get( DB_VALIDATION_FILE_PATH_ARG ) : databaseValidationFilePath; boolean newCalculateWorkloadStatistics = (newParamsMapWithShortKeys.containsKey( CALCULATE_WORKLOAD_STATISTICS_ARG )) ? Boolean.parseBoolean( newParamsMapWithShortKeys.get( CALCULATE_WORKLOAD_STATISTICS_ARG ) ) : calculateWorkloadStatistics; long newSpinnerSleepDurationAsMilli = (newParamsMapWithShortKeys.containsKey( SPINNER_SLEEP_DURATION_ARG )) ? Long.parseLong( (newParamsMapWithShortKeys.get( SPINNER_SLEEP_DURATION_ARG )) ) : spinnerSleepDurationAsMilli; boolean newPrintHelp = (newParamsMapWithShortKeys.containsKey( HELP_ARG )) ? Boolean.parseBoolean( newParamsMapWithShortKeys.get( HELP_ARG ) ) : printHelp; boolean newIgnoreScheduledStartTimes = (newParamsMapWithShortKeys.containsKey( IGNORE_SCHEDULED_START_TIMES_ARG )) ? Boolean.parseBoolean( newParamsMapWithShortKeys.get( IGNORE_SCHEDULED_START_TIMES_ARG ) ) : ignoreScheduledStartTimes; long newWarmupCount = (newParamsMapWithShortKeys.containsKey( WARMUP_COUNT_ARG )) ? Long.parseLong( newParamsMapWithShortKeys.get( WARMUP_COUNT_ARG ) ) : warmupCount; long newSkipCount = (newParamsMapWithShortKeys.containsKey( SKIP_COUNT_ARG )) ? Long.parseLong( newParamsMapWithShortKeys.get( SKIP_COUNT_ARG ) ) : skipCount; return new ConsoleAndFileDriverConfiguration( newOtherParams, newName, newDbClassName, newWorkloadClassName, newOperationCount, newThreadCount, newStatusDisplayIntervalAsSeconds, newTimeUnit, newResultDirPath, newTimeCompressionRatio, newPeerIds, newValidationParams, newDatabaseValidationFilePath, newCalculateWorkloadStatistics, newSpinnerSleepDurationAsMilli, newPrintHelp, newIgnoreScheduledStartTimes, newWarmupCount, newSkipCount ); } public String[] toArgs() throws DriverConfigurationException { List<String> argsList = new ArrayList<>(); // required core parameters if ( null != dbClassName ) { argsList.addAll( Lists.newArrayList( "-" + DB_ARG, dbClassName ) ); } if ( null != workloadClassName ) { argsList.addAll( Lists.newArrayList( "-" + WORKLOAD_ARG, workloadClassName ) ); } argsList.addAll( Lists.newArrayList( "-" + OPERATION_COUNT_ARG, Long.toString( operationCount ) ) ); // optional core parameters argsList.addAll( Lists.newArrayList( "-" + SHOW_STATUS_ARG, Long.toString( statusDisplayIntervalAsSeconds ) ) ); argsList.addAll( Lists.newArrayList( "-" + THREADS_ARG, Integer.toString( threadCount ) ) ); argsList.addAll( Lists.newArrayList( "-" + WARMUP_COUNT_ARG, Long.toString( warmupCount ) ) ); argsList.addAll( Lists.newArrayList( "-" + SKIP_COUNT_ARG, Long.toString( skipCount ) ) ); if ( null != name ) { argsList.addAll( Lists.newArrayList( "-" + NAME_ARG, name ) ); } if ( null != resultDirPath ) { argsList.addAll( Lists.newArrayList( "-" + RESULT_DIR_PATH_ARG, resultDirPath ) ); } argsList.addAll( Lists.newArrayList( "-" + TIME_UNIT_ARG, timeUnit.name() ) ); argsList.addAll( Lists.newArrayList( "-" + TIME_COMPRESSION_RATIO_ARG, Double.toString( timeCompressionRatio ) ) ); if ( !peerIds.isEmpty() ) { argsList.addAll( Lists.newArrayList( "-" + PEER_IDS_ARG, serializePeerIdsToCommandline( peerIds ) ) ); } if ( null != databaseValidationFilePath ) { argsList.addAll( Lists.newArrayList( "-" + DB_VALIDATION_FILE_PATH_ARG, databaseValidationFilePath ) ); } if ( null != validationCreationParams ) { argsList.addAll( Lists.newArrayList( "-" + CREATE_VALIDATION_PARAMS_ARG, validationCreationParams.toCommandlineString() ) ); } if ( calculateWorkloadStatistics ) { argsList.add( "-" + CALCULATE_WORKLOAD_STATISTICS_ARG ); } argsList.addAll( Lists.newArrayList( "-" + SPINNER_SLEEP_DURATION_ARG, Long.toString( spinnerSleepDurationAsMilli ) ) ); if ( printHelp ) { argsList.add( "-" + HELP_ARG ); } if ( ignoreScheduledStartTimes ) { argsList.add( "-" + IGNORE_SCHEDULED_START_TIMES_ARG ); } // additional, workload/database-related params Map<String,String> additionalParameters = MapUtils.copyExcludingKeys( paramsMap, coreConfigurationParameterKeys() ); for ( Entry<String,String> additionalParam : MapUtils.sortedEntrySet( additionalParameters ) ) { argsList.addAll( Lists.newArrayList( "-p", additionalParam.getKey(), additionalParam.getValue() ) ); } return argsList.toArray( new String[argsList.size()] ); } @Override public String toPropertiesString() throws DriverConfigurationException { StringBuilder sb = new StringBuilder(); sb.append( "# -------------------------------------\n" ); sb.append( "# -------------------------------------\n" ); sb.append( "# ----- LDBC Driver Configuration -----\n" ); sb.append( "# -------------------------------------\n" ); sb.append( "# -------------------------------------\n" ); sb.append( "\n" ); sb.append( "# ***********************\n" ); sb.append( "# *** driver defaults ***\n" ); sb.append( "# ***********************\n" ); sb.append( "\n" ); sb.append( "# status display interval (intermittently show status during benchmark execution)\n" ); sb.append( "# INT-32 (seconds)\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( SHOW_STATUS_ARG ).append( "/--" ) .append( SHOW_STATUS_ARG_LONG ).append( "\n" ); sb.append( SHOW_STATUS_ARG_LONG ).append( "=" ).append( statusDisplayIntervalAsSeconds ).append( "\n" ); sb.append( "\n" ); sb.append( "# thread pool size to use for executing operation handlers\n" ); sb.append( "# INT-32\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( THREADS_ARG ).append( "/--" ).append( THREADS_ARG_LONG ) .append( "\n" ); sb.append( THREADS_ARG_LONG ).append( "=" ).append( threadCount ).append( "\n" ); sb.append( "\n" ); sb.append( "# number of operations to execute during warmup phase of workload\n" ); sb.append( "# INT-64\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( WARMUP_COUNT_ARG ).append( "/--" ) .append( WARMUP_COUNT_ARG_LONG ).append( "\n" ); sb.append( WARMUP_COUNT_ARG_LONG ).append( "=" ).append( warmupCount ).append( "\n" ); sb.append( "\n" ); sb.append( "# number of operations to skip before beginning workload execution\n" ); sb.append( "# INT-64\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( SKIP_COUNT_ARG ).append( "/--" ) .append( SKIP_COUNT_ARG_LONG ).append( "\n" ); sb.append( SKIP_COUNT_ARG_LONG ).append( "=" ).append( skipCount ).append( "\n" ); sb.append( "\n" ); sb.append( "# name of the benchmark run\n" ); sb.append( "# STRING\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( NAME_ARG ).append( "/--" ).append( NAME_ARG_LONG ) .append( "\n" ); if ( null == name ) { sb.append( "# " ).append( NAME_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( NAME_ARG_LONG ).append( "=" ).append( name ).append( "\n" ); } sb.append( "\n" ); sb.append( "# path specifying where to write the benchmark results file\n" ); sb.append( "# STRING\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( RESULT_DIR_PATH_ARG ).append( "/--" ) .append( RESULT_DIR_PATH_ARG_LONG ).append( "\n" ); if ( null == resultDirPath ) { sb.append( "# " ).append( RESULT_DIR_PATH_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( RESULT_DIR_PATH_ARG_LONG ).append( "=" ).append( resultDirPath ).append( "\n" ); } sb.append( "\n" ); sb.append( "# time unit to use for measuring performance metrics (e.g., query response time)\n" ); sb.append( "# ENUM (" ).append( Arrays.toString( VALID_TIME_UNITS ) ).append( ")\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( TIME_UNIT_ARG ).append( "/--" ).append( TIME_UNIT_ARG_LONG ) .append( "\n" ); sb.append( TIME_UNIT_ARG_LONG ).append( "=" ).append( timeUnit ).append( "\n" ); sb.append( "\n" ); sb.append( "# used to 'compress'/'stretch' durations between operation start times to increase/decrease " + "benchmark load\n" ); sb.append( "# e.g. 2.0 = run benchmark 2x slower, 0.1 = run benchmark 10x faster\n" ); sb.append( "# DOUBLE\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( TIME_COMPRESSION_RATIO_ARG ).append( "/--" ) .append( TIME_COMPRESSION_RATIO_ARG_LONG ).append( "\n" ); sb.append( TIME_COMPRESSION_RATIO_ARG_LONG ).append( "=" ).append( timeCompressionRatio ).append( "\n" ); sb.append( "\n" ); sb.append( "# NOT USED AT PRESENT - reserved for distributed driver mode\n" ); sb.append( "# specifies the addresses of other driver processes, so they can find each other\n" ); sb.append( "# LIST (e.g., peer1|peer2|peer3)\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( PEER_IDS_ARG ).append( "/--" ).append( PEER_IDS_ARG_LONG ) .append( "\n" ); sb.append( PEER_IDS_ARG_LONG ).append( "=" ).append( serializePeerIdsToCommandline( peerIds ) ).append( "\n" ); sb.append( "\n" ); sb.append( "# enable validation that will check if the provided database implementation is correct\n" ); sb.append( "# parameter value specifies where to find the validation parameters file\n" ); sb.append( "# STRING\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( DB_VALIDATION_FILE_PATH_ARG ).append( "/--" ) .append( DB_VALIDATION_FILE_PATH_ARG_LONG ).append( "\n" ); if ( null == databaseValidationFilePath ) { sb.append( "# " ).append( DB_VALIDATION_FILE_PATH_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( DB_VALIDATION_FILE_PATH_ARG_LONG ).append( "=" ).append( databaseValidationFilePath ) .append( "\n" ); } sb.append( "\n" ); sb.append( "# generate validation parameters file for validating correctness of database implementations\n" ); sb.append( "# parameter values specify: (1) where to create the validation parameters file (2) how many " + "validation parameters to generate\n" ); sb.append( "# STRING|INT-32 (e.g., " ).append( new ConsoleAndFileValidationParamOptions( "validation_parameters.csv", 1000 ).toCommandlineString() ) .append( ")\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( CREATE_VALIDATION_PARAMS_ARG ).append( "/--" ) .append( CREATE_VALIDATION_PARAMS_ARG_LONG ).append( "\n" ); if ( null == validationCreationParams ) { sb.append( "# " ).append( CREATE_VALIDATION_PARAMS_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( CREATE_VALIDATION_PARAMS_ARG_LONG ).append( "=" ) .append( validationCreationParams.toCommandlineString() ).append( "\n" ); } sb.append( "\n" ); sb.append( "# calculate & display workload statistics (operation mix, etc.)\n" ); sb.append( "# BOOLEAN\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( CALCULATE_WORKLOAD_STATISTICS_ARG ).append( "/--" ) .append( CALCULATE_WORKLOAD_STATISTICS_ARG_LONG ).append( "\n" ); sb.append( CALCULATE_WORKLOAD_STATISTICS_ARG_LONG ).append( "=" ).append( calculateWorkloadStatistics ) .append( "\n" ); sb.append( "\n" ); sb.append( "# sleep duration (ms) injected into busy wait loops (to reduce CPU consumption)\n" ); sb.append( "# INT-64 (milliseconds)\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( SPINNER_SLEEP_DURATION_ARG ).append( "/--" ) .append( SPINNER_SLEEP_DURATION_ARG_LONG ).append( "\n" ); sb.append( SPINNER_SLEEP_DURATION_ARG_LONG ).append( "=" ).append( spinnerSleepDurationAsMilli ).append( "\n" ); sb.append( "\n" ); sb.append( "# print help string - usage instructions\n" ); sb.append( "# BOOLEAN\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( HELP_ARG ).append( "\n" ); sb.append( HELP_ARG ).append( "=" ).append( printHelp ).append( "\n" ); sb.append( "\n" ); sb.append( "# executes operations as fast as possible, ignoring their scheduled start times\n" ); sb.append( "# BOOLEAN\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( IGNORE_SCHEDULED_START_TIMES_ARG ).append( "\n" ); sb.append( IGNORE_SCHEDULED_START_TIMES_ARG ).append( "=" ).append( ignoreScheduledStartTimes ).append( "\n" ); sb.append( "\n" ); sb.append( "# ***************************************************************\n" ); sb.append( "# *** the following should be set by workload implementations ***\n" ); sb.append( "# ***************************************************************\n" ); sb.append( "\n" ); sb.append( "# fully qualified class name of the Workload (class) implementation to execute\n" ); sb.append( "# STRING (e.g., " ).append( LdbcSnbInteractiveWorkload.class.getName() ).append( ")\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( WORKLOAD_ARG ).append( "/--" ).append( WORKLOAD_ARG_LONG ) .append( "\n" ); if ( null == workloadClassName ) { sb.append( "# " ).append( WORKLOAD_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( WORKLOAD_ARG_LONG ).append( "=" ).append( workloadClassName ).append( "\n" ); } sb.append( "\n" ); sb.append( "# number of operations to generate during benchmark execution\n" ); sb.append( "# INT-64\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( OPERATION_COUNT_ARG ).append( "/--" ) .append( OPERATION_COUNT_ARG_LONG ).append( "\n" ); if ( 0 == operationCount ) { sb.append( "# " ).append( OPERATION_COUNT_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( OPERATION_COUNT_ARG_LONG ).append( "=" ).append( operationCount ).append( "\n" ); } sb.append( "\n" ); sb.append( "# ************************************************************************************\n" ); sb.append( "# *** the following should be set by vendor implementations for specific workloads ***\n" ); sb.append( "# ************************************************************************************\n" ); sb.append( "\n" ); sb.append( "# fully qualified class name of the Db (class) implementation to execute\n" ); sb.append( "# STRING (e.g., " ).append( DummyLdbcSnbInteractiveDb.class.getName() ).append( ")\n" ); sb.append( "# COMMAND: " ).append( "-" ).append( DB_ARG ).append( "/--" ).append( DB_ARG_LONG ).append( "\n" ); if ( null == dbClassName ) { sb.append( "# " ).append( DB_ARG_LONG ).append( "=" ).append( "\n" ); } else { sb.append( DB_ARG_LONG ).append( "=" ).append( dbClassName ).append( "\n" ); } // Write additional, workload/database-related keys as well Map<String,String> additionalConfigurationParameters = MapUtils.copyExcludingKeys( paramsMap, coreConfigurationParameterKeys() ); if ( !additionalConfigurationParameters.isEmpty() ) { sb.append( "\n" ); sb.append( "# ************************************************************************************\n" ); sb.append( "# *** non-core configuration parameters ***\n" ); sb.append( "# ************************************************************************************\n" ); sb.append( "\n" ); for ( Entry<String,String> configurationParameter : MapUtils .sortedEntrySet( additionalConfigurationParameters ) ) { sb.append( configurationParameter.getKey() ).append( "=" ).append( configurationParameter.getValue() ) .append( "\n" ); } } return sb.toString(); } @Override public String toString() { int padRightDistance = 32; StringBuilder sb = new StringBuilder(); sb.append( "Parameters:" ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Name:" ) ).append( name ) .append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "DB:" ) ).append( dbClassName ) .append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Workload:" ) ) .append( workloadClassName ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Operation Count:" ) ) .append( INTEGRAL_FORMAT.format( operationCount ) ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Warmup Count:" ) ) .append( INTEGRAL_FORMAT.format( warmupCount ) ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Skip Count:" ) ) .append( INTEGRAL_FORMAT.format( skipCount ) ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Worker Threads:" ) ) .append( threadCount ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Status Display Interval:" ) ).append( TEMPORAL_UTIL.milliDurationToString( TimeUnit.SECONDS.toMillis( statusDisplayIntervalAsSeconds ) ) ) .append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Time Unit:" ) ).append( timeUnit ) .append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Results Directory:" ) ) .append( resultDirPath() ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Time Compression Ratio:" ) ) .append( FLOAT_FORMAT.format( timeCompressionRatio ) ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Peer IDs:" ) ) .append( peerIds.toString() ).append( "\n" ); String validationCreationParamsString = (null == validationCreationParams) ? null : format( "File (%s) Validation Set Size (%s)", validationCreationParams.filePath(), validationCreationParams.validationSetSize ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Validation Creation Params:" ) ) .append( validationCreationParamsString ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Database Validation File:" ) ) .append( databaseValidationFilePath ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Calculate Workload Statistics:" ) ) .append( calculateWorkloadStatistics ).append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Spinner Sleep Duration:" ) ) .append( TEMPORAL_UTIL.milliDurationToString( spinnerSleepDurationAsMilli ) ).append( " / " ) .append( spinnerSleepDurationAsMilli ).append( " (ms)\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Print Help:" ) ).append( printHelp ) .append( "\n" ); sb.append( "\t" ).append( format( "%1$-" + padRightDistance + "s", "Ignore Scheduled Start Times:" ) ) .append( ignoreScheduledStartTimes ).append( "\n" ); Set<String> excludedKeys = coreConfigurationParameterKeys(); Map<String,String> filteredParamsMap = MapUtils.copyExcludingKeys( convertLongKeysToShortKeys( paramsMap ), excludedKeys ); if ( !filteredParamsMap.isEmpty() ) { sb.append( "\t" ).append( "User-defined parameters:" ).append( "\n" ); sb.append( MapUtils.prettyPrint( filteredParamsMap, "\t\t" ) ); } return sb.toString(); } @Override public boolean equals( Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } ConsoleAndFileDriverConfiguration that = (ConsoleAndFileDriverConfiguration) o; if ( calculateWorkloadStatistics != that.calculateWorkloadStatistics ) { return false; } if ( operationCount != that.operationCount ) { return false; } if ( warmupCount != that.warmupCount ) { return false; } if ( skipCount != that.skipCount ) { return false; } if ( printHelp != that.printHelp ) { return false; } if ( ignoreScheduledStartTimes != that.ignoreScheduledStartTimes ) { return false; } if ( threadCount != that.threadCount ) { return false; } if ( Double.compare( that.timeCompressionRatio, timeCompressionRatio ) != 0 ) { return false; } if ( databaseValidationFilePath != null ? !databaseValidationFilePath.equals( that.databaseValidationFilePath ) : that.databaseValidationFilePath != null ) { return false; } if ( dbClassName != null ? !dbClassName.equals( that.dbClassName ) : that.dbClassName != null ) { return false; } if ( peerIds != null ? !peerIds.equals( that.peerIds ) : that.peerIds != null ) { return false; } if ( name != null ? !name.equals( that.name ) : that.name != null ) { return false; } if ( resultDirPath != null ? !resultDirPath.equals( that.resultDirPath ) : that.resultDirPath != null ) { return false; } if ( spinnerSleepDurationAsMilli != that.spinnerSleepDurationAsMilli ) { return false; } if ( statusDisplayIntervalAsSeconds != that.statusDisplayIntervalAsSeconds ) { return false; } if ( timeUnit != that.timeUnit ) { return false; } if ( validationCreationParams != null ? !validationCreationParams.equals( that.validationCreationParams ) : that.validationCreationParams != null ) { return false; } if ( workloadClassName != null ? !workloadClassName.equals( that.workloadClassName ) : that.workloadClassName != null ) { return false; } return true; } @Override public int hashCode() { int result; long temp; result = name != null ? name.hashCode() : 0; result = 31 * result + (dbClassName != null ? dbClassName.hashCode() : 0); result = 31 * result + (workloadClassName != null ? workloadClassName.hashCode() : 0); result = 31 * result + (int) (operationCount ^ (operationCount >>> 32)); result = 31 * result + (int) (warmupCount ^ (warmupCount >>> 32)); result = 31 * result + (int) (skipCount ^ (skipCount >>> 32)); result = 31 * result + threadCount; result = 31 * result + statusDisplayIntervalAsSeconds; result = 31 * result + (timeUnit != null ? timeUnit.hashCode() : 0); result = 31 * result + (resultDirPath != null ? resultDirPath.hashCode() : 0); temp = Double.doubleToLongBits( timeCompressionRatio ); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (peerIds != null ? peerIds.hashCode() : 0); result = 31 * result + (validationCreationParams != null ? validationCreationParams.hashCode() : 0); result = 31 * result + (databaseValidationFilePath != null ? databaseValidationFilePath.hashCode() : 0); result = 31 * result + (calculateWorkloadStatistics ? 1 : 0); result = 31 * result + (int) (spinnerSleepDurationAsMilli ^ (spinnerSleepDurationAsMilli >>> 32)); result = 31 * result + (printHelp ? 1 : 0); result = 31 * result + (ignoreScheduledStartTimes ? 1 : 0); return result; } public static class ConsoleAndFileValidationParamOptions implements ValidationParamOptions { public static ConsoleAndFileValidationParamOptions fromCommandlineString( String commandlineString ) throws DriverConfigurationException { String[] commandlineStringArray = commandlineString.split( COMMANDLINE_SEPARATOR_REGEX_STRING ); if ( commandlineStringArray.length != 2 ) { throw new DriverConfigurationException( format( "Unexpected string value (%s). Should contain exactly 2 values.", commandlineString ) ); } String filePath = commandlineStringArray[0]; int validationSetSize = Integer.parseInt( commandlineStringArray[1] ); return new ConsoleAndFileValidationParamOptions( filePath, validationSetSize ); } private final String filePath; private final int validationSetSize; public ConsoleAndFileValidationParamOptions( String filePath, int validationSetSize ) { this.filePath = filePath; this.validationSetSize = validationSetSize; } @Override public String filePath() { return filePath; } @Override public int validationSetSize() { return validationSetSize; } public String toCommandlineString() { return format( "%s%s%s", filePath, COMMANDLINE_SEPARATOR_CHAR, validationSetSize ); } @Override public boolean equals( Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } ConsoleAndFileValidationParamOptions that = (ConsoleAndFileValidationParamOptions) o; if ( validationSetSize != that.validationSetSize ) { return false; } if ( filePath != null ? !filePath.equals( that.filePath ) : that.filePath != null ) { return false; } return true; } @Override public int hashCode() { int result = filePath != null ? filePath.hashCode() : 0; result = 31 * result + validationSetSize; return result; } } }