1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials are made
5  * available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at
6  * https://www.eclipse.org/legal/epl-2.0/
7  *
8  * SPDX-License-Identifier: EPL-2.0
9  *
10  * Contributors: IBM Corporation - initial API and implementation
11  *******************************************************************************/
12 
13 package org.eclipse.test.internal.performance.db;
14 
15 import java.io.File;
16 import java.io.PrintWriter;
17 import java.sql.Connection;
18 import java.sql.DriverManager;
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.sql.Timestamp;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 import org.eclipse.test.internal.performance.InternalPerformanceMeter;
32 import org.eclipse.test.internal.performance.PerformanceTestPlugin;
33 import org.eclipse.test.internal.performance.data.DataPoint;
34 import org.eclipse.test.internal.performance.data.Dim;
35 import org.eclipse.test.internal.performance.data.Sample;
36 import org.eclipse.test.internal.performance.data.Scalar;
37 import org.eclipse.test.internal.performance.eval.StatisticsSession;
38 import org.eclipse.test.performance.Dimension;
39 import org.eclipse.test.performance.Performance;
40 import org.junit.Assert;
41 
42 public class DB {
43 
44     private static final boolean DEBUG      = false;
45     private static final boolean INFO       = true;
46     private static final boolean AGGREGATE  = true;
47 
48     // the two supported DB types
49     private static final String  DERBY      = "derby";     //$NON-NLS-1$
50     private static final String  CLOUDSCAPE = "cloudscape"; //$NON-NLS-1$
51 
52     private static DB            fgDefault;
53 
findClosest(final String[] names, final String name)54     private static String findClosest(final String[] names, final String name) {
55         for (String name2 : names) {
56             if (name2.equals(name)) {
57                 return name;
58             }
59         }
60         // dw 7/16/2016: assuming this pattern is supposed to be JUST the date part of build id
61         // yyyymmdd
62         // There are probably much better patterns than even my "quick and dirty" method?
63         final Pattern pattern = Pattern.compile("20[0-9][0-9][01][0-9][0-3][0-9]"); //$NON-NLS-1$
64 // This poorly hardcoded pattern could have one of the big limitations in finding the "right" version to use in plots?
65 //      final Pattern pattern = Pattern.compile("200[3-9][01][0-9][0-3][0-9]"); //$NON-NLS-1$
66 
67         final Matcher matcher = pattern.matcher(name);
68 
69         if (!matcher.find()) {
70             return name;
71         }
72 
73         final int x = Integer.parseInt(name.substring(matcher.start(), matcher.end()));
74         int ix = -1;
75         int mind = 0;
76 
77         for (int i = 0; i < names.length; i++) {
78             matcher.reset(names[i]);
79             if (matcher.find()) {
80                 final int y = Integer.parseInt(names[i].substring(matcher.start(), matcher.end()));
81                 final int d = Math.abs(y - x);
82                 if ((ix < 0) || (d < mind)) {
83                     mind = d;
84                     ix = i;
85                 }
86             }
87         }
88 
89         if (ix >= 0) {
90             return names[ix];
91         }
92         return name;
93     }
94 
getConnection()95     public static Connection getConnection() {
96         return getDefault().fConnection;
97     }
98 
getDefault()99     synchronized static DB getDefault() {
100         if (fgDefault == null) {
101             fgDefault = new DB();
102             fgDefault.connect();
103             if (PerformanceTestPlugin.getDefault() == null) {
104                 // not started as plugin
105                 Runtime.getRuntime().addShutdownHook(new Thread() {
106 
107                     @Override
108                     public void run() {
109                         shutdown();
110                     }
111                 });
112             }
113         }
114         return fgDefault;
115     }
116 
getScenarioSeries(final String scenarioName, Variations v, final String seriesKey, final String startBuild, final String endBuild, final Dim[] dims)117     public static Scenario getScenarioSeries(final String scenarioName, Variations v, final String seriesKey,
118             final String startBuild, final String endBuild, final Dim[] dims) {
119         v = (Variations) v.clone();
120         v.put(seriesKey, new String[] { startBuild, endBuild });
121         final Scenario.SharedState ss = new Scenario.SharedState(v, scenarioName, seriesKey, dims);
122         Scenario scenario = new Scenario(scenarioName, ss);
123         final TimeSeries ts = scenario.getTimeSeries(dims[0]);
124         if (ts.getLength() < 2) {
125             v.put(seriesKey, "%"); //$NON-NLS-1$
126             final String[] names = DB.querySeriesValues(scenarioName, v, seriesKey);
127             if (names.length >= 2) {
128                 final String start = findClosest(names, startBuild);
129                 final String end = findClosest(names, endBuild);
130                 v.put(seriesKey, new String[] { start, end });
131                 scenario = new Scenario(scenarioName, ss);
132             }
133         }
134         return scenario;
135     }
136 
isActive()137     public static boolean isActive() {
138         return (fgDefault != null) && (fgDefault.getSQL() != null);
139     }
140 
141     /**
142      * @param variations
143      *            used to tag the data in the database
144      * @param sample
145      *            the sample maked as failed
146      * @param failMesg
147      *            the reason of the failure
148      */
markAsFailed(final Variations variations, final Sample sample, final String failMesg)149     public static void markAsFailed(final Variations variations, final Sample sample, final String failMesg) {
150         getDefault().internalMarkAsFailed(variations, sample, failMesg);
151     }
152 
153     /**
154      * @param names
155      * @param variationPatterns
156      * @param scenarioPattern
157      * @deprecated Use queryDistinctValues instead
158      */
159     @Deprecated
queryBuildNames(final List<String> names, final Variations variationPatterns, final String scenarioPattern)160     public static void queryBuildNames(final List<String> names, final Variations variationPatterns, final String scenarioPattern) {
161         getDefault().internalQueryDistinctValues(names, PerformanceTestPlugin.BUILD, variationPatterns, scenarioPattern);
162     }
163 
164     // Datapaoints
queryDataPoints(final Variations variations, final String scenarioName, final Set<Dim> dims)165     public static DataPoint[] queryDataPoints(final Variations variations, final String scenarioName, final Set<Dim> dims) {
166         return getDefault().internalQueryDataPoints(variations, scenarioName, dims);
167     }
168 
queryDistinctValues(final List<String> values, final String key, final Variations variationPatterns, final String scenarioPattern)169     public static void queryDistinctValues(final List<String> values, final String key, final Variations variationPatterns,
170             final String scenarioPattern) {
171         getDefault().internalQueryDistinctValues(values, key, variationPatterns, scenarioPattern);
172     }
173 
queryFailure(final String scenarioPattern, final Variations variations)174     public static Map<String, String> queryFailure(final String scenarioPattern, final Variations variations) {
175         return getDefault().internalQueryFailure(scenarioPattern, variations);
176     }
177 
178     /**
179      * @param configName
180      * @param buildPatterns
181      * @param scenarioName
182      * @return Scenario
183      * @deprecated Use queryScenarios(Variations variations, ...) instead
184      */
185     @Deprecated
queryScenario(final String configName, final String[] buildPatterns, final String scenarioName)186     public static Scenario queryScenario(final String configName, final String[] buildPatterns, final String scenarioName) {
187         final Variations variations = new Variations();
188         variations.put(PerformanceTestPlugin.CONFIG, configName);
189         variations.put(PerformanceTestPlugin.BUILD, buildPatterns);
190         return new Scenario(scenarioName, variations, PerformanceTestPlugin.BUILD, null);
191     }
192 
193     // Scenarios
194     /**
195      * Return all Scenarios that match the given config, build, and scenario name.
196      *
197      * @param configName
198      * @param buildPattern
199      * @param scenarioPattern
200      * @return array of scenarios
201      * @deprecated Use queryScenarios(Variations variations, ...) instead
202      */
203     @Deprecated
queryScenarios(final String configName, final String buildPattern, final String scenarioPattern)204     public static Scenario[] queryScenarios(final String configName, final String buildPattern, final String scenarioPattern) {
205         final Variations variations = new Variations();
206         variations.put(PerformanceTestPlugin.CONFIG, configName);
207         variations.put(PerformanceTestPlugin.BUILD, buildPattern);
208         return queryScenarios(variations, scenarioPattern, PerformanceTestPlugin.BUILD, null);
209     }
210 
211     /**
212      * @param configName
213      * @param buildPatterns
214      * @param scenarioPattern
215      * @param dimensions
216      * @return array of scenarios
217      * @deprecated Use queryScenarios(Variations variations, ...) instead
218      */
219     @Deprecated
queryScenarios(final String configName, final String[] buildPatterns, final String scenarioPattern, final Dim[] dimensions)220     public static Scenario[] queryScenarios(final String configName, final String[] buildPatterns, final String scenarioPattern,
221             final Dim[] dimensions) {
222         final Variations variations = new Variations();
223         variations.put(PerformanceTestPlugin.CONFIG, configName);
224         variations.put(PerformanceTestPlugin.BUILD, buildPatterns);
225         return queryScenarios(variations, scenarioPattern, PerformanceTestPlugin.BUILD, dimensions);
226     }
227 
228     /**
229      * Returns all Scenarios that match the given variation and scenario pattern. Every Scenario returned contains a series of
230      * datapoints specified by the seriesKey.
231      *
232      * For example to get the datapoints for For every Scenario only the specified Diemnsions are retrieved from the database.
233      *
234      * @param variations
235      * @param scenarioPattern
236      * @param seriesKey
237      * @param dimensions
238      * @return array of scenarios or <code>null</code> if an error occured.
239      */
queryScenarios(final Variations variations, final String scenarioPattern, final String seriesKey, final Dim[] dimensions)240     public static Scenario[] queryScenarios(final Variations variations, final String scenarioPattern, final String seriesKey,
241             final Dim[] dimensions) {
242         // get all Scenario names
243         final String[] scenarioNames = getDefault().internalQueryScenarioNames(variations, scenarioPattern);
244         if (scenarioNames == null) {
245             return new Scenario[0];
246         }
247         final Scenario.SharedState ss = new Scenario.SharedState(variations, scenarioPattern, seriesKey, dimensions);
248         final Scenario[] tables = new Scenario[scenarioNames.length];
249         for (int i = 0; i < scenarioNames.length; i++) {
250             tables[i] = new Scenario(scenarioNames[i], ss);
251         }
252         return tables;
253     }
254 
querySeriesValues(final String scenarioName, final Variations v, final String seriesKey)255     public static String[] querySeriesValues(final String scenarioName, final Variations v, final String seriesKey) {
256         return getDefault().internalQuerySeriesValues(v, scenarioName, seriesKey);
257     }
258 
259     /**
260      * Returns all summaries that match the given variation and scenario patterns. If scenarioPattern is null, all summary scenarios
261      * are returned that are marked as "global". If scenarioPattern is not null, it is used to filter the scenarios and only
262      * scenarios marked as "local" are returned.
263      *
264      * @param variationPatterns
265      * @param scenarioPattern
266      * @return array of summaries or <code>null</code> if an error occured.
267      */
querySummaries(final Variations variationPatterns, final String scenarioPattern)268     public static SummaryEntry[] querySummaries(final Variations variationPatterns, final String scenarioPattern) {
269         return getDefault().internalQuerySummaries(variationPatterns, scenarioPattern);
270     }
271 
shutdown()272     public static void shutdown() {
273         if (DEBUG) {
274             System.out.println("DB.shutdown"); //$NON-NLS-1$
275         }
276         if (fgDefault != null) {
277             fgDefault.disconnect();
278             fgDefault = null;
279         }
280     }
281 
282     /**
283      * Store the data contained in the given sample in the database. The data is tagged with key/value pairs from variations.
284      *
285      * @param variations
286      *            used to tag the data in the database
287      * @param sample
288      *            the sample to store
289      * @return returns true if data could be stored successfully
290      */
store(final Variations variations, final Sample sample)291     public static boolean store(final Variations variations, final Sample sample) {
292         return getDefault().internalStore(variations, sample);
293     }
294 
295     private Connection fConnection;
296 
297     private SQL        fSQL;
298 
299     private int        fStoredSamples;
300 
301     private boolean    fStoreCalled;
302 
303     // ---- private implementation
304 
305     private boolean    fIsEmbedded;
306 
307     /* fDBType is either "derby" or "cloudscape" */
308     private String     fDBType;
309 
310     /**
311      * Private constructor to block instance creation.
312      */
DB()313     private DB() {
314         // empty implementation
315     }
316 
317     /**
318      * dbloc= embed in home directory dbloc=/tmp/performance embed given location dbloc=net://localhost connect to local server
319      * dbloc=net://www.eclipse.org connect to remove server
320      */
connect()321     private void connect() {
322 
323         if (fConnection != null) {
324             return;
325         }
326 
327         if (DEBUG) {
328             DriverManager.setLogWriter(new PrintWriter(System.out));
329         }
330         final String dbloc = PerformanceTestPlugin.getDBLocation();
331         if (dbloc == null) {
332             return;
333         }
334 
335         final String dbname = PerformanceTestPlugin.getDBName();
336         String url = null;
337         final java.util.Properties info = new java.util.Properties();
338 
339         fDBType = DERBY; // assume we are using Derby
340         try {
341             if (dbloc.startsWith("net://")) { //$NON-NLS-1$
342                 // remote
343                 fIsEmbedded = false;
344                 // connect over network
345                 // connect over network
346                 final String driverName = "org.apache.derby.jdbc.ClientDriver"; //$NON-NLS-1$
347                 if (INFO) {
348                     System.out.println("Trying to connect over network, with net:// protocol; " + driverName + " ..."); //$NON-NLS-1$ //$NON-NLS-2$
349                 }
350                 Class.forName(driverName);
351                 //Class.forName("com.ibm.db2.jcc.DB2Driver"); //$NON-NLS-1$
352                 info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
353                 info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
354                 info.put("retrieveMessagesFromServerOnGetMessage", "true"); //$NON-NLS-1$ //$NON-NLS-2$
355                 url = dbloc + "/" + dbname + ";create=true"; //$NON-NLS-1$//$NON-NLS-2$
356             } else if (dbloc.startsWith("//")) { //$NON-NLS-1$
357                 // remote
358                 fIsEmbedded = false;
359                 // connect over network
360                 final String driverName = "org.apache.derby.jdbc.ClientDriver"; //$NON-NLS-1$
361                 if (INFO) {
362                     System.out
363                             .println("Trying to connect over network with // jdbc protocol;  " + driverName + " to " + dbloc + '/' + dbname + " ..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
364                 }
365                 Class.forName(driverName);
366                 info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
367                 info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
368                 info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
369                 url = dbloc + '/' + dbname;
370             } else {
371 
372                 // workaround for Derby issue:
373                 // http://nagoya.apache.org/jira/browse/DERBY-1
374                 if ("Mac OS X".equals(System.getProperty("os.name"))) { //$NON-NLS-1$ //$NON-NLS-2$
375                     System.setProperty("derby.storage.fileSyncTransactionLog", "true"); //$NON-NLS-1$ //$NON-NLS-2$
376                 }
377 
378                 // embedded
379                 fIsEmbedded = true;
380                 try {
381                     Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); //$NON-NLS-1$
382                 }
383                 catch (final ClassNotFoundException e) {
384                     Class.forName("com.ihost.cs.jdbc.CloudscapeDriver"); //$NON-NLS-1$
385                     fDBType = CLOUDSCAPE;
386                 }
387                 if (DEBUG) {
388                     System.out.println("Loaded embedded " + fDBType); //$NON-NLS-1$
389                 }
390                 File f;
391                 if (dbloc.length() == 0) {
392                     final String user_home = System.getProperty("user.home"); //$NON-NLS-1$
393                     if (user_home == null) {
394                         return;
395                     }
396                     f = new File(user_home, fDBType);
397                 } else {
398                     f = new File(dbloc);
399                 }
400                 url = new File(f, dbname).getAbsolutePath();
401                 info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
402                 info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
403                 info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
404             }
405             try {
406                 fConnection = DriverManager.getConnection("jdbc:" + fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
407             }
408             catch (final SQLException e) {
409                 System.out.println("SQLException: " + e); //$NON-NLS-1$
410                 if ("08001".equals(e.getSQLState()) && DERBY.equals(fDBType)) { //$NON-NLS-1$
411                     if (DEBUG) {
412                         System.out.println("DriverManager.getConnection failed; retrying for cloudscape"); //$NON-NLS-1$
413                     }
414                     // try Cloudscape
415                     fDBType = CLOUDSCAPE;
416                     fConnection = DriverManager.getConnection("jdbc:" + fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
417                 } else {
418                     throw e;
419                 }
420             }
421             if (INFO) {
422                 System.out.println("connect succeeded!"); //$NON-NLS-1$
423             }
424 
425             fConnection.setAutoCommit(false);
426             fSQL = new SQL(fConnection);
427             fConnection.commit();
428 
429         }
430         catch (final SQLException ex) {
431             PerformanceTestPlugin.logError(ex.getMessage());
432 
433         }
434         catch (final ClassNotFoundException e) {
435             PerformanceTestPlugin.log(e);
436         }
437     }
438 
disconnect()439     private void disconnect() {
440         if (INFO) {
441             if (fStoreCalled) {
442                 System.out.println("stored " + fStoredSamples + " new datapoints in DB"); //$NON-NLS-1$ //$NON-NLS-2$
443             } else {
444                 System.out.println("no new datapoints in DB"); //$NON-NLS-1$
445             }
446             System.out.println("disconnecting from DB"); //$NON-NLS-1$
447         }
448         if (fSQL != null) {
449             try {
450                 fSQL.dispose();
451             }
452             catch (final SQLException e1) {
453                 PerformanceTestPlugin.log(e1);
454             }
455             fSQL = null;
456         }
457         if (fConnection != null) {
458             try {
459                 fConnection.commit();
460             }
461             catch (final SQLException e) {
462                 PerformanceTestPlugin.log(e);
463             }
464             try {
465                 fConnection.close();
466             }
467             catch (final SQLException e) {
468                 PerformanceTestPlugin.log(e);
469             }
470             fConnection = null;
471         }
472 
473         if (fIsEmbedded) {
474             try {
475                 DriverManager.getConnection("jdbc:" + fDBType + ":;shutdown=true"); //$NON-NLS-1$ //$NON-NLS-2$
476             }
477             catch (final SQLException e) {
478                 final String message = e.getMessage();
479                 if (message.indexOf("system shutdown.") < 0) { //$NON-NLS-1$
480                     e.printStackTrace();
481                 }
482             }
483         }
484     }
485 
getSQL()486     SQL getSQL() {
487         return fSQL;
488     }
489 
internalMarkAsFailed(final Variations variations, final Sample sample, final String failMesg)490     private void internalMarkAsFailed(final Variations variations, final Sample sample, final String failMesg) {
491 
492         if (fSQL == null) {
493             return;
494         }
495 
496         try {
497             final int variation_id = fSQL.getVariations(variations);
498             final int scenario_id = fSQL.getScenario(sample.getScenarioID());
499 
500             fSQL.insertFailure(variation_id, scenario_id, failMesg);
501 
502             fConnection.commit();
503 
504         }
505         catch (final SQLException e) {
506             PerformanceTestPlugin.log(e);
507             try {
508                 fConnection.rollback();
509             }
510             catch (final SQLException e1) {
511                 PerformanceTestPlugin.log(e1);
512             }
513         }
514     }
515 
internalQueryDataPoints(final Variations variations, final String scenarioName, final Set<Dim> dimSet)516     private DataPoint[] internalQueryDataPoints(final Variations variations, final String scenarioName, final Set<Dim> dimSet) {
517         if (fSQL == null) {
518             return null;
519         }
520 
521         long start = System.currentTimeMillis();
522         if (DEBUG) {
523             System.out.print("	- query data points from DB for scenario " + scenarioName + "..."); //$NON-NLS-1$ //$NON-NLS-2$
524         }
525 
526         final ArrayList<DataPoint> dataPoints = new ArrayList<>();
527         try (ResultSet rs = fSQL.queryDataPoints(variations, scenarioName)){
528             if (DEBUG) {
529                 final long time = System.currentTimeMillis();
530                 System.out.println("done in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
531                 start = time;
532             }
533             while (rs.next()) {
534                 final int datapoint_id = rs.getInt(1);
535                 final int step = rs.getInt(2);
536 
537                 final HashMap<Dim, Scalar> map = new HashMap<>();
538                 try (final ResultSet rs2 = fSQL.queryScalars(datapoint_id)) {
539                     while (rs2.next()) {
540                         final int dim_id = rs2.getInt(1);
541                         final long value = rs2.getBigDecimal(2).longValue();
542                         final Dim dim = Dim.getDimension(dim_id);
543                         if (dim != null) {
544                             if ((dimSet == null) || dimSet.contains(dim)) {
545                                 map.put(dim, new Scalar(dim, value));
546                             }
547                         }
548                     }
549                     if (map.size() > 0) {
550                         dataPoints.add(new DataPoint(step, map));
551                     }
552 
553                 }
554             }
555             final int n = dataPoints.size();
556             if (DEBUG) {
557                 final long time = System.currentTimeMillis();
558                 System.out.println("		+ " + n + " datapoints created in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
559             }
560             return dataPoints.toArray(new DataPoint[n]);
561 
562         }
563         catch (final SQLException e) {
564             PerformanceTestPlugin.log(e);
565         }
566         return null;
567     }
568 
569     /*
570      *
571      */
internalQueryDistinctValues(final List<String> values, final String seriesKey, final Variations variations, final String scenarioPattern)572     private void internalQueryDistinctValues(final List<String> values, final String seriesKey, final Variations variations,
573             final String scenarioPattern) {
574         if (fSQL == null) {
575             return;
576         }
577         final long start = System.currentTimeMillis();
578         if (DEBUG) {
579             System.out.print("	- query distinct values from DB for scenario pattern '" + scenarioPattern + "'..."); //$NON-NLS-1$ //$NON-NLS-2$
580         }
581         try (ResultSet result = fSQL.queryVariations(variations.toExactMatchString(), scenarioPattern)){
582             while (result.next()) {
583                 final Variations v = new Variations();
584                 v.parseDB(result.getString(1));
585                 final String build = v.getProperty(seriesKey);
586                 if ((build != null) && !values.contains(build)) {
587                     values.add(build);
588                 }
589             }
590         } catch (final SQLException e) {
591             PerformanceTestPlugin.log(e);
592 
593         } finally {
594             if (DEBUG) {
595                 final long time = System.currentTimeMillis();
596                 System.out.println("done in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
597             }
598         }
599     }
600 
internalQueryFailure(final String scenarioPattern, final Variations variations)601     private Map<String, String> internalQueryFailure(final String scenarioPattern, final Variations variations) {
602         if (fSQL == null) {
603             return null;
604         }
605         final long start = System.currentTimeMillis();
606         if (DEBUG) {
607             System.out.print("	- query failure from DB for scenario pattern '" + scenarioPattern + "'..."); //$NON-NLS-1$ //$NON-NLS-2$
608         }
609         try (ResultSet result = fSQL.queryFailure(variations, scenarioPattern)) {
610             final Map<String, String> map = new HashMap<>();
611             while (result.next()) {
612                 final String scenario = result.getString(1);
613                 final String message = result.getString(2);
614                 map.put(scenario, message);
615             }
616             return map;
617         } catch (final SQLException e) {
618             PerformanceTestPlugin.log(e);
619 
620         } finally {
621             if (DEBUG) {
622                 final long time = System.currentTimeMillis();
623                 System.out.println("done in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
624             }
625         }
626         return null;
627     }
628 
629     /*
630      * Returns array of scenario names matching the given pattern.
631      */
internalQueryScenarioNames(final Variations variations, final String scenarioPattern)632     private String[] internalQueryScenarioNames(final Variations variations, final String scenarioPattern) {
633         if (fSQL == null) {
634             return null;
635         }
636         final long start = System.currentTimeMillis();
637         if (DEBUG) {
638             System.out.print("	- query scenario names from DB for scenario pattern '" + scenarioPattern + "'..."); //$NON-NLS-1$ //$NON-NLS-2$
639         }
640         try (ResultSet result = fSQL.queryScenarios(variations, scenarioPattern)) {
641             final ArrayList<String> scenarios = new ArrayList<>();
642             while (result.next()) {
643                 scenarios.add(result.getString(1));
644             }
645             return scenarios.toArray(new String[scenarios.size()]);
646         } catch (final SQLException e) {
647             PerformanceTestPlugin.log(e);
648         } finally {
649             if (DEBUG) {
650                 final long time = System.currentTimeMillis();
651                 System.out.println("done in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
652             }
653         }
654         return null;
655     }
656 
internalQuerySeriesValues(Variations v, final String scenarioName, final String seriesKey)657     private String[] internalQuerySeriesValues(Variations v, final String scenarioName, final String seriesKey) {
658 
659         boolean isCloned = false;
660 
661         String[] seriesPatterns = null;
662         final Object object = v.get(seriesKey);
663         if (object instanceof String[]) {
664             seriesPatterns = (String[]) object;
665         } else if (object instanceof String) {
666             seriesPatterns = new String[] { (String) object };
667         } else {
668             Assert.assertTrue(false);
669         }
670 
671         final ArrayList<String> values = new ArrayList<>();
672         for (String seriesPattern : seriesPatterns) {
673             if (seriesPattern.indexOf('%') >= 0) {
674                 if (!isCloned) {
675                     v = (Variations) v.clone();
676                     isCloned = true;
677                 }
678                 v.put(seriesKey, seriesPattern);
679                 internalQueryDistinctValues(values, seriesKey, v, scenarioName);
680             } else {
681                 values.add(seriesPattern);
682             }
683         }
684 
685         final String[] names = values.toArray(new String[values.size()]);
686 
687         boolean sort = true;
688         final Pattern pattern = Pattern.compile("20[0-9][3-9][01][0-9][0-3][0-9]"); //$NON-NLS-1$
689         final Matcher matcher = pattern.matcher(""); //$NON-NLS-1$
690         for (String name : names) {
691             matcher.reset(name);
692             if (!matcher.find()) {
693                 sort = false;
694                 break;
695             }
696         }
697         if (sort) {
698             Arrays.sort(names, (o1, o2) -> {
699                 String s1 = o1;
700                 String s2 = o2;
701 
702                 matcher.reset(s1);
703                 if (matcher.find()) {
704                     s1 = s1.substring(matcher.start());
705                 }
706 
707                 matcher.reset(s2);
708                 if (matcher.find()) {
709                     s2 = s2.substring(matcher.start());
710                 }
711 
712                 return s1.compareTo(s2);
713             });
714         }
715         return names;
716     }
717 
internalQuerySummaries(final Variations variationPatterns, final String scenarioPattern)718     private SummaryEntry[] internalQuerySummaries(final Variations variationPatterns, final String scenarioPattern) {
719         if (fSQL == null) {
720             return null;
721         }
722         final long start = System.currentTimeMillis();
723         if (DEBUG) {
724             System.out.print("	- query summaries from DB for scenario pattern '" + scenarioPattern + "'..."); //$NON-NLS-1$ //$NON-NLS-2$
725         }
726         ResultSet result = null;
727         try {
728             final List<SummaryEntry> fingerprints = new ArrayList<>();
729             if (scenarioPattern != null) {
730                 result = fSQL.querySummaryEntries(variationPatterns, scenarioPattern);
731             } else {
732                 result = fSQL.queryGlobalSummaryEntries(variationPatterns);
733             }
734             while (result.next()) {
735                 final String scenarioName = result.getString(1);
736                 final String shortName = result.getString(2);
737                 final int dim_id = result.getInt(3);
738                 final boolean isGlobal = result.getShort(4) == 1;
739                 final int comment_id = result.getInt(5);
740                 int commentKind = 0;
741                 String comment = null;
742                 if (comment_id != 0) {
743                     try (final ResultSet rs2 = fSQL.getComment(comment_id)) {
744                         if (rs2.next()) {
745                             commentKind = rs2.getInt(1);
746                             comment = rs2.getString(2);
747                         }
748                     }
749                 }
750                 if (dim_id != 0) {
751                     fingerprints.add(new SummaryEntry(scenarioName, shortName, Dim.getDimension(dim_id), isGlobal, commentKind,
752                             comment));
753                 }
754             }
755             return fingerprints.toArray(new SummaryEntry[fingerprints.size()]);
756         }
757         catch (final SQLException e) {
758             PerformanceTestPlugin.log(e);
759         }
760         finally {
761             if (result != null) {
762                 try {
763                     result.close();
764                 }
765                 catch (final SQLException e1) {
766                     // ignored
767                 }
768             }
769             if (DEBUG) {
770                 final long time = System.currentTimeMillis();
771                 System.out.println("done in " + (time - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
772             }
773         }
774         return null;
775     }
776 
internalStore(final Variations variations, final Sample sample)777     private boolean internalStore(final Variations variations, final Sample sample) {
778 
779         if ((fSQL == null) || (sample == null)) {
780             return false;
781         }
782 
783         final DataPoint[] dataPoints = sample.getDataPoints();
784         final int n = dataPoints.length;
785         if (n <= 0) {
786             return false;
787         }
788 
789         //System.out.println("store started..."); //$NON-NLS-1$
790         try {
791             // long l= System.currentTimeMillis();
792             final int variation_id = fSQL.getVariations(variations);
793             final int scenario_id = fSQL.getScenario(sample.getScenarioID());
794             final String comment = sample.getComment();
795             if (sample.isSummary()) {
796                 final boolean isGlobal = sample.isGlobal();
797 
798                 int commentId = 0;
799                 final int commentKind = sample.getCommentType();
800                 if ((commentKind == Performance.EXPLAINS_DEGRADATION_COMMENT) && (comment != null)) {
801                     commentId = fSQL.getCommentId(commentKind, comment);
802                 }
803 
804                 final Dimension[] summaryDimensions = sample.getSummaryDimensions();
805                 for (final Dimension dimension : summaryDimensions) {
806                     if (dimension instanceof Dim) {
807                         fSQL.createSummaryEntry(variation_id, scenario_id, ((Dim) dimension).getId(), isGlobal, commentId);
808                     }
809                 }
810                 final String shortName = sample.getShortname();
811                 if (shortName != null) {
812                     fSQL.setScenarioShortName(scenario_id, shortName);
813                 }
814             } else if (comment != null) {
815                 int commentId = 0;
816                 final int commentKind = sample.getCommentType();
817                 if (commentKind == Performance.EXPLAINS_DEGRADATION_COMMENT) {
818                     commentId = fSQL.getCommentId(commentKind, comment);
819                 }
820                 fSQL.createSummaryEntry(variation_id, scenario_id, 0, false, commentId); // use
821                 // special
822                 // dim
823                 // id
824                 // '0'
825                 // to
826                 // identify
827                 // summary
828                 // entry
829                 // created
830                 // to
831                 // only
832                 // handle
833                 // a
834                 // comment
835             }
836             final int sample_id = fSQL.createSample(variation_id, scenario_id, new Timestamp(sample.getStartTime()));
837 
838             if (AGGREGATE) {
839                 final StatisticsSession stats = new StatisticsSession(dataPoints);
840                 final Dim[] dims = dataPoints[0].getDimensions();
841 
842                 int datapoint_id = fSQL.createDataPoint(sample_id, 0, InternalPerformanceMeter.AVERAGE);
843                 for (final Dim dim : dims) {
844                     fSQL.insertScalar(datapoint_id, dim.getId(), (long) stats.getAverage(dim));
845                 }
846 
847                 datapoint_id = fSQL.createDataPoint(sample_id, 0, InternalPerformanceMeter.STDEV);
848                 for (final Dim dim : dims) {
849                     // see StatisticsSession
850                     final long value = Double.doubleToLongBits(stats.getStddev(dim));
851                     fSQL.insertScalar(datapoint_id, dim.getId(), value);
852                 }
853 
854                 datapoint_id = fSQL.createDataPoint(sample_id, 0, InternalPerformanceMeter.SIZE);
855                 for (final Dim dim : dims) {
856                     fSQL.insertScalar(datapoint_id, dim.getId(), stats.getCount(dim));
857                 }
858             } else {
859                 for (int i = 0; i < dataPoints.length; i++) {
860                     final DataPoint dp = dataPoints[i];
861                     final int datapoint_id = fSQL.createDataPoint(sample_id, i, dp.getStep());
862                     final Scalar[] scalars = dp.getScalars();
863                     for (final Scalar scalar : scalars) {
864                         final int dim_id = scalar.getDimension().getId();
865                         final long value = scalar.getMagnitude();
866                         fSQL.insertScalar(datapoint_id, dim_id, value);
867                     }
868                 }
869             }
870 
871             fConnection.commit();
872             fStoredSamples++;
873             fStoreCalled = true;
874 
875             // System.err.println(System.currentTimeMillis()-l);
876 
877         }
878         catch (final SQLException e) {
879             PerformanceTestPlugin.log(e);
880             try {
881                 fConnection.rollback();
882             }
883             catch (final SQLException e1) {
884                 PerformanceTestPlugin.log(e1);
885             }
886         }
887         return true;
888     }
889 }
890