Home | History | Annotate | Download | only in db
      1 /*******************************************************************************
      2  * Copyright (c) 2000, 2009 IBM Corporation and others.
      3  * All rights reserved. This program and the accompanying materials
      4  * are made available under the terms of the Eclipse Public License v1.0
      5  * which accompanies this distribution, and is available at
      6  * http://www.eclipse.org/legal/epl-v10.html
      7  *
      8  * Contributors:
      9  *     IBM Corporation - initial API and implementation
     10  *******************************************************************************/
     11 package org.eclipse.test.internal.performance.results.db;
     12 
     13 import java.io.File;
     14 import java.io.PrintWriter;
     15 import java.io.StringWriter;
     16 import java.math.BigDecimal;
     17 import java.sql.Connection;
     18 import java.sql.DriverManager;
     19 import java.sql.ResultSet;
     20 import java.sql.SQLException;
     21 import java.util.ArrayList;
     22 import java.util.Arrays;
     23 import java.util.HashMap;
     24 import java.util.List;
     25 import java.util.Map;
     26 import java.util.StringTokenizer;
     27 
     28 import org.eclipse.core.runtime.Assert;
     29 import org.eclipse.test.internal.performance.PerformanceTestPlugin;
     30 import org.eclipse.test.internal.performance.data.Dim;
     31 import org.eclipse.test.internal.performance.db.DB;
     32 import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants;
     33 import org.eclipse.test.internal.performance.results.utils.Util;
     34 import org.eclipse.test.performance.Dimension;
     35 
     36 /**
     37  * Specific and private implementation of {@link org.eclipse.test.internal.performance.db.DB} class
     38  * to get massive results from performance results database.
     39  * TODO (frederic) Should be at least a subclass of {@link DB}...
     40  */
     41 public class DB_Results {
     42 
     43 
     44 	private static final String DEFAULT_DB_BASELINE_PREFIX = "R-";
     45 	private static final Dim[] NO_DIMENSION = new Dim[0];
     46 	private static final String[] EMPTY_LIST = new String[0];
     47 	static final boolean DEBUG = false;
     48     static final boolean LOG = false;
     49 
     50     // the two supported DB types
     51     private static final String DERBY= "derby"; //$NON-NLS-1$
     52     private static final String CLOUDSCAPE= "cloudscape"; //$NON-NLS-1$
     53 
     54     private static DB_Results fgDefault;
     55 
     56     private Connection fConnection;
     57     private SQL_Results fSQL;
     58 //    private boolean fIsEmbedded;
     59     private String fDBType;	// either "derby" or "cloudscape"
     60 
     61 	    // Preferences info
     62     public static boolean DB_CONNECTION = false;
     63     private static String DB_NAME;
     64     private static String DB_LOCATION;
     65 	private static String DB_BASELINE_PREFIX = DEFAULT_DB_BASELINE_PREFIX;
     66 	private static String DB_VERSION;
     67 	private static String DB_VERSION_REF;
     68 
     69 	/**
     70 	 * Get the name of the database.
     71 	 *
     72 	 * @return The name as a string.
     73 	 */
     74     public static String getDbName() {
     75     	if (DB_NAME == null) initDbContants();
     76     	return DB_NAME;
     77     }
     78 
     79 	/**
     80 	 * Set the name of the database.
     81 	 *
     82 	 * @param dbName The name as a string.
     83 	 */
     84     public static void setDbName(String dbName) {
     85     	Assert.isNotNull(dbName);
     86     	DB_NAME = dbName;
     87     }
     88 
     89 	/**
     90 	 * Get the location of the database.
     91 	 *
     92 	 * @return The location as a string.
     93 	 */
     94     public static String getDbLocation() {
     95     	if (!DB_CONNECTION) return null;
     96     	if (DB_LOCATION == null) initDbContants();
     97     	return DB_LOCATION;
     98     }
     99 
    100 	/**
    101 	 * Set the location of the database.
    102 	 *
    103 	 * @param dbLocation The location as a string.
    104 	 */
    105     public static void setDbLocation(String dbLocation) {
    106     	Assert.isNotNull(dbLocation);
    107     	DB_LOCATION = dbLocation;
    108     }
    109 
    110 	/**
    111 	 * Get the default baseline prefix.
    112 	 *
    113 	 * @return The prefix as a string.
    114 	 */
    115     public static String getDbBaselinePrefix() {
    116     	return DB_BASELINE_PREFIX;
    117     }
    118 
    119 	/**
    120 	 * Set the baseline prefix of the database.
    121 	 *
    122 	 * @param baselinePrefix The prefix as a string.
    123 	 */
    124     public static void setDbDefaultBaselinePrefix(String baselinePrefix) {
    125     	Assert.isNotNull(baselinePrefix);
    126     	Assert.isTrue(baselinePrefix.startsWith(DEFAULT_DB_BASELINE_PREFIX));
    127     	DB_BASELINE_PREFIX = baselinePrefix;
    128     }
    129 
    130 	/**
    131 	 * Get the baseline reference version of the database.
    132 	 *
    133 	 * @return The version as a string.
    134 	 */
    135     public static String getDbBaselineRefVersion() {
    136     	if (DB_VERSION_REF == null) initDbContants();
    137     	return DB_VERSION_REF;
    138     }
    139 
    140 	/**
    141 	 * Get the version of the database.
    142 	 *
    143 	 * @return The version as a string.
    144 	 */
    145     public static String getDbVersion() {
    146     	if (DB_VERSION == null) initDbContants();
    147     	return DB_VERSION;
    148     }
    149 
    150 	/**
    151 	 * Set the version of the database.
    152 	 *
    153 	 * @param version The version as a string.
    154 	 */
    155     public static void setDbVersion(String version) {
    156     	Assert.isNotNull(version);
    157     	Assert.isTrue(version.startsWith("v3"));
    158     	DB_VERSION = version;
    159     }
    160 
    161 	/**
    162 	 * Update the database constants from a new database location.
    163 	 * @param connected Tells whether the database should be connected or not.
    164 	 * @param databaseLocation The database location.
    165 	 * 	May be a path to a local folder or a net address
    166 	 * 	(see {@link IPerformancesConstants#NETWORK_DATABASE_LOCATION}).
    167 	 */
    168 	public static boolean updateDbConstants(boolean connected, int eclipseVersion, String databaseLocation) {
    169 		if (DB_CONNECTION != connected || DB_LOCATION == null || DB_NAME == null ||
    170 			((databaseLocation == null && !DB_LOCATION.equals(IPerformancesConstants.NETWORK_DATABASE_LOCATION)) ||
    171 					!DB_LOCATION.equals(databaseLocation)) ||
    172 			!DB_NAME.equals(IPerformancesConstants.DATABASE_NAME_PREFIX + eclipseVersion)) {
    173 			shutdown();
    174 			DB_CONNECTION = connected;
    175 			DB_LOCATION = databaseLocation == null ? IPerformancesConstants.NETWORK_DATABASE_LOCATION : databaseLocation;
    176 			DB_NAME = IPerformancesConstants.DATABASE_NAME_PREFIX + eclipseVersion;
    177 			DB_VERSION = "v" + eclipseVersion;
    178 			DB_VERSION_REF = "R-3." + (eclipseVersion % 10 - 1);
    179 			if (connected) {
    180 				return getDefault().fSQL != null;
    181 			}
    182 		}
    183 		return true;
    184 	}
    185 
    186 	/**
    187 	 * Returns a title including DB version and name.
    188 	 *
    189 	 * @return A title as a string.
    190 	 */
    191 	public static String getDbTitle() {
    192     	if (!DB_CONNECTION) return null;
    193 		String title = "Eclipse " + DB_VERSION + " - ";
    194 		if (DB_LOCATION.startsWith("net:")) {
    195 			title += " Network DB";
    196 		} else {
    197 			title += " Local DB";
    198 		}
    199 		return title;
    200 	}
    201 
    202 	/**
    203 	 * The list of all the configurations (i.e. machine) stored in the database.
    204 	 */
    205 	private static String[] CONFIGS;
    206 
    207 	/**
    208 	 * The list of all the components stored in the database.
    209 	 */
    210 	private static String[] COMPONENTS;
    211 
    212 	/**
    213 	 * The list of all the builds stored in the database.
    214 	 */
    215 	private static String[] BUILDS;
    216 
    217 	/**
    218 	 * The list of all the dimensions stored in the database.
    219 	 */
    220 	private static int[] DIMENSIONS;
    221 
    222 	/**
    223 	 * The default dimension used to display results (typically in fingerprints).
    224 	 */
    225 	private static Dim DEFAULT_DIM;
    226 	private static int DEFAULT_DIM_INDEX;
    227 
    228 	/**
    229 	 * The list of all the dimensions displayed while generating results.
    230 	 */
    231 	private static Dim[] RESULTS_DIMENSIONS;
    232 
    233 	/**
    234 	 * The list of all the VMs stored in the database.
    235 	 */
    236 	private static String[] VMS;
    237 
    238 	/**
    239 	 * The list of possible test boxes.
    240 	 * <p>
    241 	 * Only used if no specific configurations are specified
    242 	 * (see {@link PerformanceResults#readAll(String, String[][], String, File, int, org.eclipse.core.runtime.IProgressMonitor)}.
    243 	 * </p>
    244 	 * Note that this is a copy of the the property "eclipse.perf.config.descriptors"
    245 	 * defined in org.eclipse.releng.eclipsebuilder/eclipse/helper.xml file
    246 	 */
    247 	private static String[] CONFIG_DESCRIPTIONS;
    248 
    249 	/**
    250 	 * The list of known Eclipse components.
    251 	 */
    252 	private final static String[] ECLIPSE_COMPONENTS = {
    253 		"org.eclipse.ant", //$NON-NLS-1$
    254 		"org.eclipse.compare", //$NON-NLS-1$
    255 		"org.eclipse.core", //$NON-NLS-1$
    256 		"org.eclipse.help", //$NON-NLS-1$
    257 		"org.eclipse.jdt.core", //$NON-NLS-1$
    258 		"org.eclipse.jdt.debug", //$NON-NLS-1$
    259 		"org.eclipse.jdt.text", //$NON-NLS-1$
    260 		"org.eclipse.jdt.ui", //$NON-NLS-1$
    261 		"org.eclipse.jface", //$NON-NLS-1$
    262 		"org.eclipse.osgi", //$NON-NLS-1$
    263 		"org.eclipse.pde.api.tools", //$NON-NLS-1$
    264 		"org.eclipse.pde.ui", //$NON-NLS-1$
    265 		"org.eclipse.swt", //$NON-NLS-1$
    266 		"org.eclipse.team", //$NON-NLS-1$
    267 		"org.eclipse.ua", //$NON-NLS-1$
    268 		"org.eclipse.ui" //$NON-NLS-1$
    269 	};
    270 	private static String[] KNOWN_COMPONENTS = ECLIPSE_COMPONENTS;
    271 
    272 
    273 	    // Store debug info
    274 	final static StringWriter DEBUG_STR_WRITER;
    275 	final static PrintWriter DEBUG_WRITER;
    276 	static {
    277 		if (DEBUG) {
    278 			DEBUG_STR_WRITER= new StringWriter();
    279 			DEBUG_WRITER= new PrintWriter(DEBUG_STR_WRITER);
    280 		} else {
    281 			DEBUG_STR_WRITER= null;
    282 			DEBUG_WRITER= null;
    283 		}
    284 	}
    285 
    286     // Store log info
    287     final static StringWriter LOG_STR_WRITER = new StringWriter();
    288     final static LogWriter LOG_WRITER = new LogWriter();
    289     static class LogWriter extends PrintWriter {
    290 		long[] starts = new long[10];
    291 		long[] times = new long[10];
    292     	StringBuffer[] buffers = new StringBuffer[10];
    293     	int depth = -1, max = -1;
    294     	public LogWriter() {
    295 	        super(LOG_STR_WRITER);
    296         }
    297 		void starts(String log) {
    298     		if (++this.depth >= this.buffers.length) {
    299     			System.arraycopy(this.times, 0, this.times = new long[this.depth+10], 0, this.depth);
    300     			System.arraycopy(this.buffers, 0, this.buffers= new StringBuffer[this.depth+10], 0, this.depth);
    301     		}
    302     		StringBuffer buffer = this.buffers[this.depth];
    303     		if (this.buffers[this.depth] == null) buffer = this.buffers[this.depth] = new StringBuffer();
    304     		buffer.append(log);
    305     		this.starts[this.depth] = System.currentTimeMillis();
    306     		if (this.depth > this.max) this.max = this.depth;
    307     	}
    308 		void ends(String log) {
    309 			if (this.depth < 0)
    310 				throw new RuntimeException("Invalid call to ends (missing corresponding starts call)!"); //$NON-NLS-1$
    311     		this.buffers[this.depth].append(log);
    312     		if (this.depth > 0) {
    313     			this.times[this.depth] += System.currentTimeMillis() - this.starts[this.depth];
    314     			this.depth--;
    315     			return;
    316     		}
    317     		for (int i=0; i<this.max; i++) {
    318 	    		print(this.buffers[i].toString());
    319 	    		print(" ( in "); //$NON-NLS-1$
    320 	    		print(this.times[this.depth]);
    321     			println("ms)"); //$NON-NLS-1$
    322     		}
    323     		this.depth = this.max = -1;
    324 			this.starts = new long[10];
    325 			this.times = new long[10];
    326     		this.buffers = new StringBuffer[10];
    327     	}
    328 		public String toString() {
    329 	        return LOG_STR_WRITER.toString();
    330         }
    331     }
    332 
    333 	// Data storage from queries
    334 	static String LAST_CURRENT_BUILD, LAST_BASELINE_BUILD;
    335 	private static int BUILDS_LENGTH;
    336 	private static String[] SCENARII;
    337 	private static String[] COMMENTS;
    338 
    339     //---- private implementation
    340 
    341 	/**
    342      * Private constructor to block instance creation.
    343      */
    344     private DB_Results() {
    345     	// empty implementation
    346     }
    347 
    348     synchronized static DB_Results getDefault() {
    349         if (fgDefault == null) {
    350             fgDefault= new DB_Results();
    351             fgDefault.connect();
    352             if (PerformanceTestPlugin.getDefault() == null) {
    353             	// not started as plugin
    354 	            Runtime.getRuntime().addShutdownHook(
    355 	                new Thread() {
    356 	                    public void run() {
    357 	                    	shutdown();
    358 	                    }
    359 	                }
    360 	            );
    361             }
    362         } else if (fgDefault.fSQL == null) {
    363         	fgDefault.connect();
    364         }
    365         return fgDefault;
    366     }
    367 
    368     public static void shutdown() {
    369         if (fgDefault != null) {
    370             fgDefault.disconnect();
    371             fgDefault= null;
    372             BUILDS = null;
    373             LAST_BASELINE_BUILD = null;
    374             LAST_CURRENT_BUILD = null;
    375             DIMENSIONS = null;
    376             CONFIGS = null;
    377             COMPONENTS = null;
    378             SCENARII = null;
    379             COMMENTS = null;
    380             DB_VERSION = null;
    381             DB_VERSION_REF = null;
    382             DEFAULT_DIM =null;
    383             DEFAULT_DIM_INDEX = -1;
    384             RESULTS_DIMENSIONS = null;
    385             VMS = null;
    386             CONFIG_DESCRIPTIONS = null;
    387             KNOWN_COMPONENTS = ECLIPSE_COMPONENTS;
    388         }
    389         if (DEBUG) {
    390         	DEBUG_WRITER.println("DB.shutdown"); //$NON-NLS-1$
    391         	System.out.println(DEBUG_STR_WRITER.toString());
    392         }
    393         if (LOG) {
    394         	System.out.println(LOG_STR_WRITER.toString());
    395         }
    396     }
    397 
    398 /**
    399  * Return the build id from a given name.
    400  *
    401  * @param name The build name (eg. I20070615-1200)
    402  * @return The id of the build (ie. the index in the {@link #BUILDS} list)
    403  */
    404 static int getBuildId(String name) {
    405 	if (BUILDS == null) return -1;
    406 	return Arrays.binarySearch(BUILDS, name, Util.BUILD_DATE_COMPARATOR);
    407 }
    408 
    409 /**
    410  * Return the build name from a given id.
    411  *
    412  * @param id The build id
    413  * @return The name of the build (eg. I20070615-1200)
    414  */
    415 static String getBuildName(int id) {
    416 	if (BUILDS == null) return null;
    417 	return BUILDS[id];
    418 }
    419 
    420 /**
    421  * Returns all the builds names read from the database.
    422  *
    423  * @return The list of all builds names matching the scenario pattern used while reading data
    424  */
    425 public static String[] getBuilds() {
    426 	if (BUILDS == null) {
    427 		queryAllVariations("%"); //$NON-NLS-1$
    428 	}
    429 	if (BUILDS_LENGTH == 0) return EMPTY_LIST;
    430 	String[] builds = new String[BUILDS_LENGTH];
    431 	System.arraycopy(BUILDS, 0, builds, 0, BUILDS_LENGTH);
    432 	return builds;
    433 }
    434 
    435 /**
    436  * Returns the number of builds stored int the database.
    437  *
    438  * @return The number of builds stored in the database.
    439  */
    440 public static int getBuildsNumber() {
    441 	if (BUILDS == null) {
    442 		queryAllVariations("%"); //$NON-NLS-1$
    443 	}
    444 	return BUILDS_LENGTH;
    445 }
    446 
    447 /**
    448  * Get component name from a scenario.
    449  *
    450  * @param scenarioName The name of the scenario
    451  * @return The component name
    452  */
    453 static String getComponentNameFromScenario(String scenarioName) {
    454 	int length = KNOWN_COMPONENTS.length;
    455 	for (int i=0; i<length; i++) {
    456 		if (scenarioName.startsWith(KNOWN_COMPONENTS[i])) {
    457 			return KNOWN_COMPONENTS[i];
    458 		}
    459 	}
    460 	StringTokenizer tokenizer = new StringTokenizer(scenarioName, ".");
    461 	StringBuffer buffer = new StringBuffer(tokenizer.nextToken());
    462 	if (tokenizer.hasMoreTokens()) {
    463 		buffer.append('.');
    464 		buffer.append(tokenizer.nextToken());
    465 		if (tokenizer.hasMoreTokens()) {
    466 			buffer.append('.');
    467 			buffer.append(tokenizer.nextToken());
    468 		}
    469 	}
    470 	String componentName = buffer.toString();
    471 	System.err.println(scenarioName+" does not belongs to a known Eclipse component. So use scenario prefix "+componentName+" as component name by default and add it to the know components"); //$NON-NLS-1$
    472 	System.arraycopy(KNOWN_COMPONENTS, 0, KNOWN_COMPONENTS = new String[length+1], 0, length);
    473 	KNOWN_COMPONENTS[length] = componentName;
    474 	return componentName;
    475 }
    476 
    477 /**
    478  * Get all components read from database.
    479  *
    480  * @return A list of component names matching the given pattern
    481  */
    482 public static String[] getComponents() {
    483 	if (COMPONENTS == null) return EMPTY_LIST;
    484 	int length = COMPONENTS.length;
    485 	String[] components = new String[length];
    486 	System.arraycopy(COMPONENTS, 0, components, 0, length);
    487 	return components;
    488 }
    489 
    490 /**
    491  * Return the name of the configuration from the given id.
    492  *
    493  * @param id The index of the configuration in the stored list.
    494  * @return The name of the configuration (eg. eclipseperflnx1_R3.3)
    495  */
    496 static String getConfig(int id) {
    497 	return CONFIGS[id];
    498 }
    499 
    500 /**
    501  * Get all configurations read from the database.
    502  *
    503  * @return A list of configuration names
    504  */
    505 public static String[] getConfigs() {
    506 	if (CONFIGS == null) return EMPTY_LIST;
    507 	int length = CONFIGS.length;
    508 	String[] configs = new String[length];
    509 	System.arraycopy(CONFIGS, 0, configs, 0, length);
    510 	return configs;
    511 }
    512 
    513 /**
    514  * Set the default dimension used for performance results.
    515  */
    516 public static void setConfigs(String[] configs) {
    517 	CONFIGS = configs;
    518 }
    519 
    520 /**
    521  * Get all configurations read from the database.
    522  *
    523  * @return A list of configuration names
    524  */
    525 public static String[] getConfigDescriptions() {
    526 	if (CONFIG_DESCRIPTIONS == null) {
    527 		if (CONFIGS == null) return null;
    528 		int length = CONFIGS.length;
    529 		CONFIG_DESCRIPTIONS = new String[length];
    530 		String[][] configDescriptors = PerformanceTestPlugin.getConfigDescriptors();
    531 		int cdLength = configDescriptors.length;
    532 		for (int i = 0; i < length; i++) {
    533 			boolean found = false;
    534 			for (int j = 0; j < cdLength; j++) {
    535 				if (configDescriptors[j][0].equals(CONFIGS[i])) {
    536 			        CONFIG_DESCRIPTIONS[i] = configDescriptors[j][1];
    537 			        found = true;
    538 			        break;
    539 				}
    540 			}
    541 			if (!found) {
    542 				String kind = CONFIGS[i].indexOf("epwin") < 0 ? "Linux" : "Win XP";
    543 				CONFIG_DESCRIPTIONS[i] = kind+" perf test box "+CONFIGS[i].substring(5);
    544 			}
    545         }
    546 	}
    547 	int length = CONFIG_DESCRIPTIONS.length;
    548 	String[] descriptions = new String[length];
    549 	System.arraycopy(CONFIG_DESCRIPTIONS, 0, descriptions, 0, length);
    550 	return descriptions;
    551 }
    552 
    553 /**
    554  * Set the default dimension used for performance results.
    555  */
    556 public static void setConfigDescriptions(String[] descriptions) {
    557 	CONFIG_DESCRIPTIONS = descriptions;
    558 }
    559 
    560 /**
    561  * Get all dimensions read from the database.
    562  *
    563  * @return A list of dimensions.
    564  */
    565 public static Dim[] getDimensions() {
    566 	if (DIMENSIONS == null) return NO_DIMENSION;
    567 	int length = DIMENSIONS.length;
    568 	Dim[] dimensions = new Dim[length];
    569 	for (int i = 0; i < length; i++) {
    570 		Dimension dimension = PerformanceTestPlugin.getDimension(DIMENSIONS[i]);
    571 		if (dimension == null) {
    572 			throw new RuntimeException("There is an unsupported dimension stored in the database: " +DIMENSIONS[i]);
    573 		}
    574 		dimensions[i] = (Dim) dimension;
    575     }
    576 	return dimensions;
    577 }
    578 
    579 /**
    580  * Return the default dimension used for performance results.
    581  *
    582  * @return The {@link Dim default dimension}.
    583  */
    584 public static Dim getDefaultDimension() {
    585 	if (DEFAULT_DIM == null) {
    586 		DEFAULT_DIM = (Dim) PerformanceTestPlugin.getDefaultDimension();
    587 	}
    588 	return DEFAULT_DIM;
    589 }
    590 
    591 /**
    592  * Set the default dimension used for performance results.
    593  */
    594 public static void setDefaultDimension(String dim) {
    595 	DEFAULT_DIM = (Dim) PerformanceTestPlugin.getDimension(dim);
    596 	if (DIMENSIONS != null) {
    597 		DEFAULT_DIM_INDEX = Arrays.binarySearch(DIMENSIONS, DEFAULT_DIM.getId());
    598 	}
    599 }
    600 
    601 public static Dim[] getResultsDimensions() {
    602 	if (RESULTS_DIMENSIONS == null) {
    603 		Dimension[] resultsDimensions = PerformanceTestPlugin.getResultsDimensions();
    604 		int length = resultsDimensions.length;
    605 		RESULTS_DIMENSIONS = new Dim[length];
    606 		for (int i = 0; i < length; i++) {
    607 			RESULTS_DIMENSIONS[i] = (Dim) resultsDimensions[i];
    608 		}
    609 	}
    610 	return RESULTS_DIMENSIONS;
    611 }
    612 
    613 /**
    614  * Set the default dimension used for performance results.
    615  */
    616 public static void setResultsDimensions(String[] dimensions) {
    617 	int length = dimensions.length;
    618 	RESULTS_DIMENSIONS = new Dim[length];
    619 	for (int i = 0; i < length; i++) {
    620 		RESULTS_DIMENSIONS[i] = (Dim) PerformanceTestPlugin.getDimension(dimensions[i]);
    621 	}
    622 }
    623 
    624 /**
    625  * Return the default dimension used for performance results.
    626  *
    627  * @return The {@link Dim default dimension}.
    628  */
    629 public static int getDefaultDimensionIndex() {
    630 	if (DEFAULT_DIM == null || DEFAULT_DIM_INDEX == -1) {
    631 		getDefaultDimension(); // init default dimension
    632 		getDimensions(); // init dimensions
    633 		DEFAULT_DIM_INDEX = Arrays.binarySearch(DIMENSIONS, DEFAULT_DIM.getId());
    634 	}
    635 	return DEFAULT_DIM_INDEX;
    636 }
    637 
    638 /**
    639  * Return the ID of the last baseline build before the given date.
    640  *
    641  * @param date The date the baseline must be run before. If <code>null</code>
    642  * 	return the last baseline build stored in the DB.
    643  *
    644  * @return the ID of the last baseline build before the given date or
    645  * 	<code>null</code> if none was run before it...
    646  */
    647 public static String getLastBaselineBuild(String date) {
    648 	if (BUILDS == null) {
    649 		queryAllVariations("%"); //$NON-NLS-1$
    650 	}
    651 	if (date == null) {
    652 		if (LAST_BASELINE_BUILD == null) {
    653 			return BUILDS[0];
    654 		}
    655 		return LAST_BASELINE_BUILD;
    656 	}
    657 	String lastBaselineBuild = null;
    658 	for (int i=0; i<BUILDS_LENGTH; i++) {
    659 		String build = BUILDS[i];
    660 		if (build.startsWith(DB_VERSION_REF)) {
    661 			String buildDate = build.substring(build.indexOf('_')+1);
    662 			if (buildDate.compareTo(date) < 0) {
    663 				if (lastBaselineBuild == null || build.compareTo(lastBaselineBuild) > 0) {
    664 					lastBaselineBuild = build;
    665 				}
    666 			}
    667 		}
    668 	}
    669 	if (lastBaselineBuild == null) {
    670 		return BUILDS[0];
    671 	}
    672 	return lastBaselineBuild;
    673 }
    674 
    675 /**
    676  * Return the ID of the last baseline build.
    677  *
    678  * @return the ID of the last baseline build.
    679  */
    680 public static String getLastCurrentBuild() {
    681 	if (BUILDS == null) {
    682 		queryAllVariations("%"); //$NON-NLS-1$
    683 	}
    684 	return LAST_CURRENT_BUILD;
    685 }
    686 
    687 /**
    688  * Returns all the scenarios names read from the database.
    689  *
    690  * @return The list of all scenarios matching the pattern for a given build.
    691  * @see #internalQueryBuildScenarios(String, String)
    692  */
    693 public static List getScenarios() {
    694 	return Arrays.asList(SCENARII);
    695 }
    696 
    697 /**
    698  * Init the constants if necessary.
    699  */
    700 public static void initDbContants() {
    701 	if (DB_LOCATION == null) {
    702 		DB_LOCATION = PerformanceTestPlugin.getDBLocation();
    703 		if (DB_LOCATION == null) {
    704 			new RuntimeException("Cannot connect to the DB without a location!");
    705 		}
    706 	}
    707 	if (DB_NAME == null) {
    708 		DB_NAME = PerformanceTestPlugin.getDBName();
    709 		if (DB_NAME == null) {
    710 			new RuntimeException("Cannot connect to the DB without a name!");
    711 		}
    712 	}
    713 	if (DB_VERSION == null) {
    714 		DB_VERSION = "v" + DB_NAME.substring(DB_NAME.length()-2);
    715 		DB_VERSION_REF = "R-3."+(Character.digit(DB_NAME.charAt(DB_NAME.length()-1), 10)-1);
    716 	}
    717 }
    718 
    719 /**
    720  * Get all scenarios read from database.
    721  *
    722  * @return A list of all scenario names matching the default pattern
    723  */
    724 public static Map queryAllScenarios() {
    725 	return getDefault().internalQueryBuildScenarios("%", null); //$NON-NLS-1$
    726 }
    727 
    728 /**
    729  * Get all scenarios read from database matching a given pattern.
    730  * Note that all scenarios are returned if the pattern is <code>null</code>.
    731  *
    732  * @param scenarioPattern The pattern of the requested scenarios
    733  * @return A map of all scenarios matching the given pattern.
    734  * 	The map keys are component names and values are the scenarios list for
    735  * 	each component.
    736  */
    737 static Map queryAllScenarios(String scenarioPattern) {
    738 	String pattern = scenarioPattern==null ? "%" : scenarioPattern; //$NON-NLS-1$
    739 	return getDefault().internalQueryBuildScenarios(pattern, null);
    740 }
    741 
    742 /**
    743  * Get all scenarios read from database matching a given pattern.
    744  * Note that all scenarios are returned if the pattern is <code>null</code>.
    745  *
    746  * @param scenarioPattern The pattern of the requested scenarios
    747  * @param buildName The build name
    748  * @return A list of scenario names matching the given pattern
    749  */
    750 static Map queryAllScenarios(String scenarioPattern, String buildName) {
    751 	return getDefault().internalQueryBuildScenarios(scenarioPattern, buildName);
    752 }
    753 
    754 /**
    755  * Get all variations read from database matching a given configuration pattern.
    756  *
    757  * @param configPattern The pattern of the requested configurations
    758  */
    759 static void queryAllVariations(String configPattern) {
    760 	getDefault().internalQueryAllVariations(configPattern);
    761 }
    762 
    763 /**
    764  * Get all summaries from DB for a given scenario and configuration pattern
    765  *
    766  * @param scenarioResults The scenario results where to store data
    767  * @param configPattern The configuration pattern concerned by the query
    768  * @param builds All builds to get summaries, if <code>null</code>, then all DB
    769  * 	builds will be concerned.
    770  */
    771 static void queryScenarioSummaries(ScenarioResults scenarioResults, String configPattern, String[] builds) {
    772 	getDefault().internalQueryScenarioSummaries(scenarioResults, configPattern, builds);
    773 }
    774 
    775 /**
    776  * Query and store all values for given scenario results
    777  *
    778  * @param scenarioResults The scenario results where the values has to be put
    779  * @param configPattern The pattern of the configuration concerned by the query
    780  * @param buildName Name of the last build on which data were stored locally
    781  *
    782 */
    783 static void queryScenarioValues(ScenarioResults scenarioResults, String configPattern, String buildName) {
    784 	getDefault().internalQueryScenarioValues(scenarioResults, configPattern, buildName);
    785 }
    786 
    787 /**
    788  * dbloc=						embed in home directory
    789  * dbloc=/tmp/performance			embed given location
    790  * dbloc=net://localhost			connect to local server
    791  * dbloc=net://www.eclipse.org	connect to remove server
    792  */
    793 private void connect() {
    794 
    795 	if (this.fConnection != null || !DB_CONNECTION)
    796 		return;
    797 
    798 	if (DEBUG) DriverManager.setLogWriter(new PrintWriter(System.out));
    799 
    800 	// Init DB location and name if not already done
    801 	if (DB_LOCATION == null) {
    802 		initDbContants();
    803 	}
    804 
    805 	String url = null;
    806 	java.util.Properties info = new java.util.Properties();
    807 
    808 	if (DEBUG) {
    809 		DEBUG_WRITER.println();
    810 		DEBUG_WRITER.println("==========================================================="); //$NON-NLS-1$
    811 		DEBUG_WRITER.println("Database debug information stored while processing"); //$NON-NLS-1$
    812 	}
    813 	if (LOG) {
    814 		LOG_WRITER.println();
    815 		LOG_WRITER.println("==========================================================="); //$NON-NLS-1$
    816 		LOG_WRITER.println("Database log information stored while processing"); //$NON-NLS-1$
    817 	}
    818 
    819 	this.fDBType = DERBY; // assume we are using Derby
    820 	try {
    821 		if (DB_LOCATION.startsWith("net://")) { //$NON-NLS-1$
    822 			// remote
    823 //			fIsEmbedded = false;
    824 			// connect over network
    825 			if (DEBUG)
    826 				DEBUG_WRITER.println("Trying to connect over network..."); //$NON-NLS-1$
    827 			Class.forName("com.ibm.db2.jcc.DB2Driver"); //$NON-NLS-1$
    828 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
    829 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
    830 			info.put("retrieveMessagesFromServerOnGetMessage", "true"); //$NON-NLS-1$ //$NON-NLS-2$
    831 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
    832 			url = DB_LOCATION + '/' + DB_NAME;
    833 		} else if (DB_LOCATION.startsWith("//")) { //$NON-NLS-1$
    834 			// remote
    835 //			fIsEmbedded = false;
    836 			// connect over network
    837 			if (DEBUG)
    838 				DEBUG_WRITER.println("Trying to connect over network..."); //$NON-NLS-1$
    839 			Class.forName("org.apache.derby.jdbc.ClientDriver"); //$NON-NLS-1$
    840 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
    841 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
    842 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
    843 			url = DB_LOCATION + '/' + DB_NAME;
    844 		} else {
    845 			// workaround for Derby issue:
    846 			// http://nagoya.apache.org/jira/browse/DERBY-1
    847 			if ("Mac OS X".equals(System.getProperty("os.name"))) //$NON-NLS-1$//$NON-NLS-2$
    848 				System.setProperty("derby.storage.fileSyncTransactionLog", "true"); //$NON-NLS-1$ //$NON-NLS-2$
    849 
    850 			// embedded
    851 			try {
    852 				Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); //$NON-NLS-1$
    853 //				fIsEmbedded = true;
    854 			} catch (ClassNotFoundException e) {
    855 				Class.forName("com.ihost.cs.jdbc.CloudscapeDriver"); //$NON-NLS-1$
    856 				this.fDBType = CLOUDSCAPE;
    857 			}
    858 			if (DEBUG)
    859 				DEBUG_WRITER.println("Loaded embedded " + this.fDBType); //$NON-NLS-1$
    860 			File f;
    861 			if (DB_LOCATION.length() == 0) {
    862 				String user_home = System.getProperty("user.home"); //$NON-NLS-1$
    863 				if (user_home == null)
    864 					return;
    865 				f = new File(user_home, this.fDBType);
    866 			} else
    867 				f = new File(DB_LOCATION);
    868 			url = new File(f, DB_NAME).getAbsolutePath();
    869 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
    870 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
    871 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
    872 		}
    873 		try {
    874 			this.fConnection = DriverManager.getConnection("jdbc:" + this.fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
    875 		} catch (SQLException e) {
    876 			if ("08001".equals(e.getSQLState()) && DERBY.equals(this.fDBType)) { //$NON-NLS-1$
    877 				if (DEBUG)
    878 					DEBUG_WRITER.println("DriverManager.getConnection failed; retrying for cloudscape"); //$NON-NLS-1$
    879 				// try Cloudscape
    880 				this.fDBType = CLOUDSCAPE;
    881 				this.fConnection = DriverManager.getConnection("jdbc:" + this.fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
    882 			} else
    883 				throw e;
    884 		}
    885 		if (DEBUG)
    886 			DEBUG_WRITER.println("connect succeeded!"); //$NON-NLS-1$
    887 
    888 		this.fConnection.setAutoCommit(false);
    889 		this.fSQL = new SQL_Results(this.fConnection);
    890 		this.fConnection.commit();
    891 
    892 	} catch (SQLException ex) {
    893 		PerformanceTestPlugin.logError(ex.getMessage());
    894 
    895 	} catch (ClassNotFoundException e) {
    896 		PerformanceTestPlugin.log(e);
    897 	}
    898 }
    899 
    900 private void disconnect() {
    901 	if (DEBUG)
    902 		DEBUG_WRITER.println("disconnecting from DB"); //$NON-NLS-1$
    903 	if (this.fSQL != null) {
    904 		try {
    905 			this.fSQL.dispose();
    906 		} catch (SQLException e1) {
    907 			PerformanceTestPlugin.log(e1);
    908 		}
    909 		this.fSQL = null;
    910 	}
    911 	if (this.fConnection != null) {
    912 		try {
    913 			this.fConnection.commit();
    914 		} catch (SQLException e) {
    915 			PerformanceTestPlugin.log(e);
    916 		}
    917 		try {
    918 			this.fConnection.close();
    919 		} catch (SQLException e) {
    920 			PerformanceTestPlugin.log(e);
    921 		}
    922 		this.fConnection = null;
    923 	}
    924 
    925 	/*
    926 	if (fIsEmbedded) {
    927 		try {
    928 			DriverManager.getConnection("jdbc:" + fDBType + ":;shutdown=true"); //$NON-NLS-1$ //$NON-NLS-2$
    929 		} catch (SQLException e) {
    930 			String message = e.getMessage();
    931 			if (message.indexOf("system shutdown.") < 0) //$NON-NLS-1$
    932 				e.printStackTrace();
    933 		}
    934 	}
    935 	*/
    936 }
    937 
    938 /*
    939  * Return the index of the given configuration in the stored list.
    940  */
    941 private int getConfigId(String config) {
    942 	if (CONFIGS == null) return -1;
    943 	return Arrays.binarySearch(CONFIGS, config);
    944 }
    945 
    946 SQL_Results getSQL() {
    947     return this.fSQL;
    948 }
    949 
    950 /*
    951  * Query all comments from database
    952  */
    953 private void internalQueryAllComments() {
    954 	if (this.fSQL == null) return;
    955 	if (COMMENTS != null) return;
    956 	long start = System.currentTimeMillis();
    957 	if (DEBUG) DEBUG_WRITER.print("		[DB query all comments..."); //$NON-NLS-1$
    958 	ResultSet result = null;
    959 	try {
    960 		String[] comments = null;
    961 		result = this.fSQL.queryAllComments();
    962 		while (result.next()) {
    963 			int commentID = result.getInt(1);
    964 			// Ignore kind as there's only one
    965 			// int commentKind = result.getInt(2);
    966 			String comment = result.getString(3);
    967 			if (comments == null) {
    968 				comments = new String[commentID+10];
    969 			} else if (commentID >= comments.length) {
    970 				int length = comments.length;
    971 				System.arraycopy(comments, 0, comments = new String[commentID+10], 0, length);
    972 			}
    973 			comments[commentID] = comment;
    974 		}
    975 		COMMENTS = comments;
    976 	} catch (SQLException e) {
    977 		PerformanceTestPlugin.log(e);
    978 	} finally {
    979 		if (result != null) {
    980 			try {
    981 				result.close();
    982 			} catch (SQLException e1) {
    983 				// ignored
    984 			}
    985 		}
    986 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
    987 	}
    988 }
    989 
    990 /*
    991  * Query all variations. This method stores all config and build names.
    992  */
    993 private void internalQueryAllVariations(String configPattern) {
    994 	if (this.fSQL == null) return;
    995 	if (BUILDS != null) return;
    996 	long start = System.currentTimeMillis();
    997 	if (DEBUG) {
    998 		DEBUG_WRITER.print("	- DB query all variations for configuration pattern: "+configPattern); //$NON-NLS-1$
    999 		DEBUG_WRITER.print("..."); //$NON-NLS-1$
   1000 	}
   1001 	ResultSet result = null;
   1002 	try {
   1003 		CONFIGS = null;
   1004 		BUILDS = null;
   1005 		BUILDS_LENGTH = 0;
   1006 		result = this.fSQL.queryAllVariations(configPattern);
   1007 		while (result.next()) {
   1008 			String variation = result.getString(1); //  something like "||build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
   1009 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
   1010 			tokenizer.nextToken(); 												// 'build'
   1011 			storeBuildName(tokenizer.nextToken());				// 'I20070615-1200'
   1012 			tokenizer.nextToken();												// 'config'
   1013 			storeConfig(tokenizer.nextToken()); 	// 'eclipseperfwin2_R3.3'
   1014 			tokenizer.nextToken();												// 'jvm'
   1015 			storeVm(tokenizer.nextToken());					// 'sun'
   1016 		}
   1017 		if (BUILDS_LENGTH == 0) {
   1018 			BUILDS = EMPTY_LIST;
   1019 		}
   1020 	} catch (SQLException e) {
   1021 		PerformanceTestPlugin.log(e);
   1022 	} finally {
   1023 		if (result != null) {
   1024 			try {
   1025 				result.close();
   1026 			} catch (SQLException e1) {
   1027 				// ignored
   1028 			}
   1029 		}
   1030 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
   1031 	}
   1032 }
   1033 
   1034 private Map internalQueryBuildScenarios(String scenarioPattern, String buildName) {
   1035 	if (this.fSQL == null) return null;
   1036 	long start = System.currentTimeMillis();
   1037 	if (DEBUG) {
   1038 		DEBUG_WRITER.print("	- DB query all scenarios"); //$NON-NLS-1$
   1039 		if (scenarioPattern != null) DEBUG_WRITER.print(" with pattern "+scenarioPattern); //$NON-NLS-1$
   1040 		if (buildName != null) DEBUG_WRITER.print(" for build: "+buildName); //$NON-NLS-1$
   1041 	}
   1042 	ResultSet result = null;
   1043 	Map allScenarios = new HashMap();
   1044 	try {
   1045 		if (buildName == null) {
   1046 			result = this.fSQL.queryBuildAllScenarios(scenarioPattern);
   1047 		} else {
   1048 			result = this.fSQL.queryBuildScenarios(scenarioPattern, buildName);
   1049 		}
   1050 		int previousId = -1;
   1051 		List scenarios = null;
   1052 		List scenariosNames = new ArrayList();
   1053 		for (int i = 0; result.next(); i++) {
   1054 			int id = result.getInt(1);
   1055 			String name = result.getString(2);
   1056 			scenariosNames.add(name);
   1057 			String shortName = result.getString(3);
   1058 			int component_id = storeComponent(getComponentNameFromScenario(name));
   1059 			if (component_id != previousId) {
   1060 				allScenarios.put(COMPONENTS[component_id], scenarios = new ArrayList());
   1061 				previousId = component_id;
   1062 			}
   1063 			scenarios.add(new ScenarioResults(id, name, shortName));
   1064 		}
   1065 		SCENARII = new String[scenariosNames.size()];
   1066 		scenariosNames.toArray(SCENARII);
   1067 	} catch (SQLException e) {
   1068 		PerformanceTestPlugin.log(e);
   1069 	} finally {
   1070 		if (result != null) {
   1071 			try {
   1072 				result.close();
   1073 			} catch (SQLException e1) { // ignored
   1074 			}
   1075 		}
   1076 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
   1077 	}
   1078 	return allScenarios;
   1079 }
   1080 
   1081 private void internalQueryScenarioValues(ScenarioResults scenarioResults, String configPattern, String buildName) {
   1082 	if (this.fSQL == null) return;
   1083 	if (DEBUG) {
   1084 		DEBUG_WRITER.print("	- DB query all data points for config pattern: "+configPattern+" for scenario: " + scenarioResults.getShortName()); //$NON-NLS-1$ //$NON-NLS-2$
   1085 		if (buildName != null) DEBUG_WRITER.print(" for build: "+buildName); //$NON-NLS-1$
   1086 	}
   1087 	internalQueryAllVariations(configPattern); // need to read all variations to have all build names
   1088 	ResultSet result = null;
   1089 	try {
   1090 		int count = 0;
   1091 
   1092 		result = buildName == null
   1093 			?	this.fSQL.queryScenarioDataPoints(configPattern, scenarioResults.getId())
   1094 			:	this.fSQL.queryScenarioBuildDataPoints(configPattern, scenarioResults.getId(), buildName);
   1095 		while (result.next()) {
   1096 			int dp_id = result.getInt(1);
   1097 			int step = result.getInt(2);
   1098 			String variation = result.getString(3); //  something like "|build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
   1099 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
   1100 			tokenizer.nextToken(); 													// 'build'
   1101 			int build_id = getBuildId(tokenizer.nextToken());		// 'I20070615-1200'
   1102 			tokenizer.nextToken();													// 'config'
   1103 			int config_id = getConfigId(tokenizer.nextToken()); 		// 'eclipseperflnx3'
   1104 			ResultSet rs2 = this.fSQL.queryDimScalars(dp_id);
   1105 			while (rs2.next()) {
   1106 				int dim_id = rs2.getInt(1);
   1107 				storeDimension(dim_id);
   1108 				BigDecimal decimalValue = rs2.getBigDecimal(2);
   1109 				long value = decimalValue.longValue();
   1110 				if (build_id >= 0) { // build id may be negative (i.e. not stored in the array) if new run starts while we're getting results
   1111 					scenarioResults.setValue(build_id, dim_id, config_id, step, value);
   1112 				}
   1113 				count++;
   1114 			}
   1115 		}
   1116 		if (LOG) LOG_WRITER.ends("		-> " + count + " values read");  //$NON-NLS-1$ //$NON-NLS-2$
   1117 	} catch (SQLException e) {
   1118 		PerformanceTestPlugin.log(e);
   1119 	} finally {
   1120 		if (result != null) {
   1121 			try {
   1122 				result.close();
   1123 			} catch (SQLException e1) {
   1124 				// ignored
   1125 			}
   1126 		}
   1127 	}
   1128 }
   1129 
   1130 private void internalQueryScenarioSummaries(ScenarioResults scenarioResults, String config, String[] builds) {
   1131 	if (this.fSQL == null) return;
   1132 	long start = System.currentTimeMillis();
   1133 	if (DEBUG) {
   1134 		DEBUG_WRITER.print("	- DB query all summaries for scenario '"+scenarioResults.getShortName()+"' of '"+config+"' config"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
   1135 	}
   1136 	internalQueryAllComments();
   1137 	ResultSet result = null;
   1138 	try {
   1139 		int scenarioID = scenarioResults.getId();
   1140 		// First try to get summaries of elapsed process dimension
   1141 		result = this.fSQL.queryScenarioSummaries(scenarioID, config, builds);
   1142 		while (result.next()) {
   1143 			String variation = result.getString(1); //  something like "|build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
   1144 			int summaryKind = result.getShort(2);
   1145 			int comment_id = result.getInt(3);
   1146 			int dim_id = result.getInt(4);
   1147 			if (dim_id != 0) storeDimension(dim_id);
   1148 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
   1149 			tokenizer.nextToken(); 													// 'build'
   1150 			String buildName = tokenizer.nextToken();					// 'I20070615-1200'
   1151 			tokenizer.nextToken();													// 'config'
   1152 			int config_id = getConfigId(tokenizer.nextToken()); 		// 'eclipseperflnx3'
   1153 			int build_id = getBuildId(buildName);
   1154 			if (build_id >= 0) {
   1155 				scenarioResults.setInfos(config_id, build_id, dim_id==0?-1:summaryKind, COMMENTS[comment_id]);
   1156 			}
   1157 		}
   1158 	} catch (SQLException e) {
   1159 		PerformanceTestPlugin.log(e);
   1160 	} finally {
   1161 		if (result != null) {
   1162 			try {
   1163 				result.close();
   1164 			} catch (SQLException e1) {
   1165 				// ignored
   1166 			}
   1167 		}
   1168 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
   1169 	}
   1170 }
   1171 
   1172 /*
   1173  * Store a build name in the dynamic list.
   1174  * The list is sorted alphabetically.
   1175  */
   1176 private int storeBuildName(String build) {
   1177 	boolean isVersion = build.startsWith(DB_BASELINE_PREFIX);
   1178 	if (BUILDS == null) {
   1179 		BUILDS = new String[1];
   1180 		BUILDS[BUILDS_LENGTH++] = build;
   1181 		if (isVersion) {
   1182 			LAST_BASELINE_BUILD = build;
   1183 		} else {
   1184 			LAST_CURRENT_BUILD = build;
   1185 		}
   1186 		return 0;
   1187 	}
   1188 	int idx = Arrays.binarySearch(BUILDS, build, Util.BUILD_DATE_COMPARATOR);
   1189 	if (idx >= 0) return idx;
   1190 	int index = -idx-1;
   1191 	int length = BUILDS.length;
   1192 	if (BUILDS_LENGTH == length) {
   1193 		String[] array = new String[length+1];
   1194 		if (index > 0) System.arraycopy(BUILDS, 0, array, 0, index);
   1195 		array[index] = build;
   1196 		if (index < length) {
   1197 			System.arraycopy(BUILDS, index, array, index+1, length-index);
   1198 		}
   1199 		BUILDS = array;
   1200 	}
   1201 	BUILDS_LENGTH++;
   1202 	if (isVersion) {
   1203 		if (LAST_BASELINE_BUILD == null || LAST_CURRENT_BUILD == null) {
   1204 			LAST_BASELINE_BUILD = build;
   1205 		} else {
   1206 			String buildDate = LAST_CURRENT_BUILD.substring(1, 9)+LAST_CURRENT_BUILD.substring(10, LAST_CURRENT_BUILD.length());
   1207 			String baselineDate = LAST_BASELINE_BUILD.substring(LAST_BASELINE_BUILD.indexOf('_')+1);
   1208 			if (build.compareTo(LAST_BASELINE_BUILD) > 0 && baselineDate.compareTo(buildDate) < 0) {
   1209 				LAST_BASELINE_BUILD = build;
   1210 			}
   1211 		}
   1212 	} else {
   1213 		if (LAST_CURRENT_BUILD == null || build.substring(1).compareTo(LAST_CURRENT_BUILD.substring(1)) >= 0) {
   1214 			LAST_CURRENT_BUILD = build;
   1215 		}
   1216 	}
   1217 	return index;
   1218 }
   1219 
   1220 /*
   1221  * Store a configuration in the dynamic list.
   1222  * The list is sorted alphabetically.
   1223  */
   1224 private int storeConfig(String config) {
   1225 	if (CONFIGS== null) {
   1226 		CONFIGS= new String[1];
   1227 		CONFIGS[0] = config;
   1228 		return 0;
   1229 	}
   1230 	int idx = Arrays.binarySearch(CONFIGS, config);
   1231 	if (idx >= 0) return idx;
   1232 	int length = CONFIGS.length;
   1233 	System.arraycopy(CONFIGS, 0, CONFIGS = new String[length+1], 0, length);
   1234 	CONFIGS[length] = config;
   1235 	Arrays.sort(CONFIGS);
   1236 	return length;
   1237 }
   1238 
   1239 /*
   1240  * Store a component in the dynamic list. The list is sorted alphabetically.
   1241  * Note that the array is rebuilt each time a new component is discovered
   1242  * as this does not happen so often (e.g. eclipse only has 10 components).
   1243  */
   1244 private int storeComponent(String component) {
   1245 	if (COMPONENTS== null) {
   1246 		COMPONENTS= new String[1];
   1247 		COMPONENTS[0] = component;
   1248 		return 0;
   1249 	}
   1250 	int idx = Arrays.binarySearch(COMPONENTS, component);
   1251 	if (idx >= 0) return idx;
   1252 	int length = COMPONENTS.length;
   1253 	System.arraycopy(COMPONENTS, 0, COMPONENTS = new String[length+1], 0, length);
   1254 	COMPONENTS[length] = component;
   1255 	Arrays.sort(COMPONENTS);
   1256 	return length;
   1257 }
   1258 
   1259 /*
   1260  * Store a dimension in the dynamic list. The list is sorted in ascending order.
   1261  * Note that the array is rebuilt each time a new dimension is discovered
   1262  * as this does not happen so often (e.g. eclipse only stores two dimensions).
   1263  */
   1264 public static int storeDimension(int id) {
   1265 	if (DIMENSIONS == null) {
   1266 		DIMENSIONS = new int[1];
   1267 		DIMENSIONS[0] = id;
   1268 		return 0;
   1269 	}
   1270 	int idx = Arrays.binarySearch(DIMENSIONS, id);
   1271 	if (idx >= 0) return idx;
   1272 	int length = DIMENSIONS.length;
   1273 	System.arraycopy(DIMENSIONS, 0, DIMENSIONS = new int[length+1], 0, length);
   1274 	DIMENSIONS[length] = id;
   1275 	Arrays.sort(DIMENSIONS);
   1276 	return length;
   1277 }
   1278 
   1279 /*
   1280  * Store a dimension in the dynamic list. The list is sorted alphabetically.
   1281  * Note that the array is rebuilt each time a new dimension is discovered
   1282  * as this does not happen so often (e.g. eclipse only stores two dimensions).
   1283  */
   1284 private int storeVm(String vm) {
   1285 	if (VMS == null) {
   1286 		VMS = new String[1];
   1287 		VMS[0] = vm;
   1288 		return 0;
   1289 	}
   1290 	int idx = Arrays.binarySearch(VMS, vm);
   1291 	if (idx >= 0) return idx;
   1292 	int length = VMS.length;
   1293 	System.arraycopy(VMS, 0, VMS = new String[length+1], 0, length);
   1294 	VMS[length] = vm;
   1295 	Arrays.sort(VMS);
   1296 	return length;
   1297 }
   1298 
   1299 }
   1300