Unified ATDB access for viewer and importer.
Change-Id: Ic661d039f433a25d84ded62cf3e129291874d420
Signed-off-by: Raphael Weber <raphael.weber@vector.com>
diff --git a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
index 7d63809..1988aea 100644
--- a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
+++ b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
@@ -14,7 +14,6 @@
package org.eclipse.app4mc.atdb._import.btf;
import java.lang.reflect.InvocationTargetException;
-import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
@@ -25,6 +24,7 @@
import java.util.Set;
import java.util.stream.Collectors;
+import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.app4mc.atdb._import.btf.model.BTFCombiState;
import org.eclipse.app4mc.atdb._import.btf.model.BTFCountMetric;
import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityState;
@@ -35,9 +35,9 @@
public class ATDBMetricCalculator implements IRunnableWithProgress {
- private final Connection con;
+ private final ATDBConnection con;
- public ATDBMetricCalculator(final Connection con) {
+ public ATDBMetricCalculator(final ATDBConnection con) {
this.con = con;
}
@@ -170,12 +170,10 @@
}
// execute all statements
- this.con.setAutoCommit(false);
- metricStmt.executeBatch();
+ this.con.executeBatchStatements(metricStmt);
monitor.worked(70);
- statement.executeBatch();
+ this.con.executeBatchStatements(statement);
monitor.worked(30);
- this.con.setAutoCommit(true);
} catch (SQLException e) {
throw new InvocationTargetException(e);
}
diff --git a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/BTFImporter.java b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/BTFImporter.java
index 2121bd5..cd6bac9 100644
--- a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/BTFImporter.java
+++ b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/BTFImporter.java
@@ -17,7 +17,6 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
@@ -32,6 +31,7 @@
import java.util.Scanner;
import java.util.Set;
+import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityType;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
@@ -40,9 +40,9 @@
public class BTFImporter implements IRunnableWithProgress {
private final String btfFile;
- private final Connection con;
+ private final ATDBConnection con;
- public BTFImporter(final Connection con, final String btfFile) {
+ public BTFImporter(final ATDBConnection con, final String btfFile) {
this.con = con;
this.btfFile = btfFile;
}
@@ -64,7 +64,8 @@
final PreparedStatement evStmt = this.con.prepareStatement("INSERT INTO traceEvent VALUES(?, ?,"
+ "(SELECT id FROM entity WHERE name = ?), ?,"//
+ "(SELECT id FROM entity WHERE name = ?), ?,"//
- + "(SELECT id FROM eventType WHERE name = ?), ?)")) {
+ + "(SELECT id FROM eventType WHERE name = ?), ?)");
+ final Statement propStmt = this.con.createStatement()) {
final long fileSize = new File(this.btfFile).length();
long currentTimestamp = Long.MIN_VALUE;
int currentSQCNR = 0;
@@ -188,26 +189,16 @@
}
}
}
+ executeEntityInsertStatements(entStmt);
+ executePropertyInsertStatements(propStmt);
readingBTFMonitor.done();
+
final SubMonitor writeEventsMonitor = subMon.split(1);
writeEventsMonitor.beginTask("Writing events to data base...", 1);
- this.con.setAutoCommit(false);
- metaStmt.executeBatch();
- entTStmt.executeBatch();
- executeEntityInsertStatements(entStmt);
- instStmt.executeBatch();
- evTStmt.executeBatch();
- evStmt.executeBatch();
- executePropertyInsertStatements(this.con.createStatement());
+ this.con.executeBatchStatements(metaStmt, entTStmt, entStmt, instStmt, evTStmt, evStmt, propStmt);
writeEventsMonitor.done();
} catch (final IOException | SQLException e) {
throw new InvocationTargetException(e);
- } finally {
- try {
- this.con.setAutoCommit(true);
- } catch (SQLException e) {
- throw new InvocationTargetException(e);
- }
}
}
@@ -230,7 +221,6 @@
eStmt.setString(2, entityType);
eStmt.addBatch();
}
- eStmt.executeBatch();
}
private final Set<String> instNames = new HashSet<>();
@@ -302,7 +292,6 @@
for (final String st : statements) {
stmt.addBatch(st);
}
- stmt.executeBatch();
}
}
diff --git a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ImportTransformation.java b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ImportTransformation.java
index 4c57de3..04dcdc7 100644
--- a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ImportTransformation.java
+++ b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ImportTransformation.java
@@ -16,10 +16,10 @@
package org.eclipse.app4mc.atdb._import.btf;
import java.lang.reflect.InvocationTargetException;
-import java.sql.Connection;
import java.sql.SQLException;
import org.eclipse.app4mc.atdb.ATDBBuilder;
+import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityType;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
@@ -47,17 +47,16 @@
public void run(final IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
if (!this.btfFile.isEmpty() && !this.atdbFile.isEmpty()) {
final SubMonitor subMon = SubMonitor.convert(progressMonitor, "Converting BTF trace to ATDB...", 100);
- try (final ATDBBuilder atdbBuilder = new ATDBBuilder(this.atdbFile)) {
+ try (final ATDBConnection con = new ATDBConnection(atdbFile, true)) {
final SubMonitor createATDBMonitor = subMon.split(1);
createATDBMonitor.beginTask("Creating empty ATDB...", 1);
- atdbBuilder.createBasicDBStructure().createBasicViews()
+ final ATDBBuilder atdbBuilder = new ATDBBuilder(con).createBasicDBStructure().createBasicViews()
.createOptionalAndTemporaryTables(BTFEntityType.literals, this.persistTraceEvents);
if (this.persistTraceEvents)
atdbBuilder.createOptionalViews(BTFEntityType.literals);
createATDBMonitor.done();
final SubMonitor btfImportMonitor = subMon.split(69);
- final Connection con = atdbBuilder.getCurrentConnection();
final IRunnableWithProgress btfImporter = new BTFImporter(con, this.btfFile);
btfImporter.run(btfImportMonitor);
btfImportMonitor.done();
diff --git a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/model/BTFEntityType.java b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/model/BTFEntityType.java
index 3a481fa..73d98a5 100644
--- a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/model/BTFEntityType.java
+++ b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/model/BTFEntityType.java
@@ -37,7 +37,7 @@
private final String entityTypeName;
private BTFEntityType(final Class<? extends Enum<?>> eventTypeEnum, final String... traceAlias) {
- this.traceAliases = Arrays.asList(traceAlias);
+ this.traceAliases = Collections.unmodifiableList(Arrays.asList(traceAlias));
String entityTypeName = eventTypeEnum.getSimpleName();
entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase();
this.entityTypeName = entityTypeName;
@@ -54,8 +54,8 @@
}
@Override
- public String getTraceAliases() {
- return this.traceAliases.stream().map(ta -> "'" + ta + "'").collect(Collectors.joining(", "));
+ public List<String> getTraceAliases() {
+ return this.traceAliases;
}
public static BTFEntityType getForName(final String name) {
@@ -63,7 +63,7 @@
}
@Override
- public Set<? extends Enum<?>> getPossibleEvents() {
+ public Set<Enum<?>> getPossibleEvents() {
return BTFEntityState.getPossibleEventsFor(this);
}
diff --git a/plugins/org.eclipse.app4mc.atdb.metrics/META-INF/MANIFEST.MF b/plugins/org.eclipse.app4mc.atdb.metrics/META-INF/MANIFEST.MF
index af0d7c0..883dcde 100644
--- a/plugins/org.eclipse.app4mc.atdb.metrics/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.app4mc.atdb.metrics/META-INF/MANIFEST.MF
@@ -8,9 +8,8 @@
org.eclipse.ui,
org.eclipse.ui.ide,
org.eclipse.nebula.widgets.nattable.core,
- org.sqlite.jdbc,
- com.google.guava,
- org.eclipse.ui.views.properties.tabbed
+ org.eclipse.app4mc.atdb,
+ com.google.guava
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-Vendor: Eclipse APP4MC
diff --git a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DBViewer.java b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DBViewer.java
index 0716e87..e10b71d 100644
--- a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DBViewer.java
+++ b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DBViewer.java
@@ -13,7 +13,6 @@
package org.eclipse.app4mc.atdb.metrics;
-import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -59,8 +58,6 @@
public class DBViewer extends EditorPart implements IEditorPart {
- private DatabaseAccess dbAccess = null;
-
private Map<String, DBResultRowDataProvider> view2ResultRowDataProvider = new LinkedHashMap<>();
private CTabFolder cTabFolder = null;
@@ -97,12 +94,11 @@
if (input instanceof FileEditorInput) {
final FileEditorInput fei = (FileEditorInput) input;
final IFile dbFile = fei.getFile();
- try {
- this.dbAccess = new DatabaseAccess(dbFile);
+ try (final DatabaseAccess dbAccess = new DatabaseAccess(dbFile)){
this.view2ResultRowDataProvider.put(Messages.DBViewer_processTimeMetricsTitle,
- this.dbAccess.getMinAvgMaxProcessMetricValues(Arrays.asList("time"), true)); //$NON-NLS-1$
+ dbAccess.getMinAvgMaxProcessMetricValues(Arrays.asList("time"), true)); //$NON-NLS-1$
this.view2ResultRowDataProvider.put(Messages.DBViewer_runnableTimeMetricsTitle,
- this.dbAccess.getMinAvgMaxRunnableMetricValues(Arrays.asList("time"), true, true)); //$NON-NLS-1$
+ dbAccess.getMinAvgMaxRunnableMetricValues(Arrays.asList("time"), true, true)); //$NON-NLS-1$
}
catch (final Exception e) {
MessageDialog.openError(site.getShell(), Messages.DBViewer_fileErrorTitle,
@@ -192,17 +188,4 @@
this.cTabFolder.forceFocus();
}
}
-
- @Override
- public void dispose() {
- if (this.dbAccess != null) {
- try {
- this.dbAccess.closeDatabaseConnection();
- }
- catch (final SQLException e) {
- throw new RuntimeException(e);
- }
- }
- super.dispose();
- }
}
diff --git a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
index f0a1025..b4689a3 100644
--- a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
+++ b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
@@ -13,25 +13,21 @@
package org.eclipse.app4mc.atdb.metrics;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Properties;
import java.util.stream.Collectors;
+import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.core.resources.IFile;
-public class DatabaseAccess {
+public class DatabaseAccess implements AutoCloseable {
- private final Connection traceDbConnection;
+ private final ATDBConnection traceDbConnection;
private final String timeBase;
private final Map<String, DBResultRowDataProvider> query2Result;
@@ -68,27 +64,22 @@
return prependedColumns.isEmpty() ? "" : indent + prependedColumns.stream().map(c -> c.entityId2Name).collect(Collectors.joining(",\n" + indent)) + ",\n";
}
- public DatabaseAccess(final IFile databaseFile) throws SQLException, ClassNotFoundException {
- Class.forName("org.sqlite.JDBC"); //$NON-NLS-1$
- String connectionStr = "jdbc:sqlite:"; //$NON-NLS-1$
- connectionStr += databaseFile.getLocation().toFile().toString();
- final Properties properties = new Properties();
- properties.put("open_mode", "1"); //$NON-NLS-1$ //$NON-NLS-2$
- this.traceDbConnection = DriverManager.getConnection(connectionStr, properties);
+ public DatabaseAccess(final IFile databaseFile) throws SQLException {
+ this.traceDbConnection = new ATDBConnection(databaseFile.getLocation().toFile().toString());
- String timeBase = "?";
final String timeUnitSelection = "SELECT value FROM metaInformation WHERE name LIKE 'timeBase';"; //$NON-NLS-1$
- try (final Statement statement = this.traceDbConnection.createStatement();
- final ResultSet resultSet = statement.executeQuery(timeUnitSelection)) {
- if (resultSet.next()) {
- timeBase = resultSet.getString(1);
+ this.timeBase = this.traceDbConnection.queryAndMapResult(timeUnitSelection, rs -> {
+ if (rs.next()) {
+ return rs.getString(1);
+ } else {
+ return "?";
}
- }
- this.timeBase = timeBase;
+ });
this.query2Result = new LinkedHashMap<>();
}
- public void closeDatabaseConnection() throws SQLException {
+ @Override
+ public void close() throws SQLException {
this.query2Result.clear();
this.traceDbConnection.close();
}
@@ -151,9 +142,8 @@
+ "FROM precalculated\n"
+ "ORDER BY " + getPrependedColumns2Order(prependColumns) + entityTypeLabel.toLowerCase() + "Id, metricId;"; //$NON-NLS-1$
if (!this.query2Result.containsKey(queryString)) {
- try (final Statement statement = this.traceDbConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
- this.query2Result.put(queryString, DBResultRowDataProvider.of(statement.executeQuery(queryString), groupColumnIndices));
- }
+ this.traceDbConnection.queryAndConsumeResult(queryString, rs ->
+ this.query2Result.put(queryString, DBResultRowDataProvider.of(rs, groupColumnIndices)));
}
return this.query2Result.get(queryString);
}
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
index 48fedd6..03c48c1 100644
--- a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
@@ -13,125 +13,104 @@
package org.eclipse.app4mc.atdb;
-import java.sql.Connection;
-import java.sql.DriverManager;
import java.sql.SQLException;
-import java.sql.Statement;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-public class ATDBBuilder implements AutoCloseable {
+public class ATDBBuilder {
- private final Connection connection;
- private final Statement statement;
+ private final ATDBConnection connection;
- public ATDBBuilder(final String atdbFile) throws SQLException {
- try {
- Class.forName("org.sqlite.JDBC"); // init JDBC driver
- } catch (ClassNotFoundException e) {
- // fail silently. DriverManager will throw an SQL exception complaining about a missing driver
- }
- this.connection = DriverManager.getConnection("jdbc:sqlite:" + atdbFile);
- this.statement = connection.createStatement();
- this.statement.setQueryTimeout(30); // set timeout to 30 sec.
- this.statement.executeUpdate("PRAGMA foreign_keys = ON;"); // enable foreign key checks
- }
-
- public Connection getCurrentConnection() {
- return this.connection;
- }
-
- @Override
- public void close() throws SQLException {
- this.connection.close();
+ public ATDBBuilder(final ATDBConnection connection) throws SQLException {
+ this.connection = connection;
}
public ATDBBuilder createBasicDBStructure() throws SQLException {
// create meta info table
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS metaInformation (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS metaInformation (\n"
+ " name TEXT PRIMARY KEY,\n"
+ " value TEXT\n"
+ ");");
// create entity type table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entityType (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entityType (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE\n"
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS entityTypeIndex ON entityType(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS entityTypeIndex ON entityType(name);");
// create entity table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entity (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entity (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE,\n"
+ " entityTypeId REFERENCES entityType(id)\n"
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS entityIndex ON entity(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS entityIndex ON entity(name);");
// create entity instance table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entityInstance (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entityInstance (\n"
+ " entityId REFERENCES entity(id),\n"
+ " sqcnr INTEGER,\n"
+ " PRIMARY KEY(entityId, sqcnr)\n"
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS entityInstanceIndex ON entityInstance(entityId, sqcnr);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS entityInstanceIndex ON entityInstance(entityId, sqcnr);");
// create event type table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS eventType (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS eventType (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE\n"
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS eventTypeIndex ON eventType(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS eventTypeIndex ON eventType(name);");
// create property table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS property (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS property (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE,\n"
+ " type TEXT"//
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS propertyIndex ON property(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS propertyIndex ON property(name);");
// create property value table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS propertyValue (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS propertyValue (\n"
+ " entityId REFERENCES entity(id),\n"
+ " propertyId REFERENCES property(id),\n"
+ " sqcnr INTEGER DEFAULT 0,\n"
+ " value TEXT,\n"
+ " PRIMARY KEY(entityId, propertyId, sqcnr)\n"
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS propertyValueIndex ON propertyValue(entityId, propertyId);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS propertyValueIndex ON propertyValue(entityId, propertyId);");
// create event table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS event (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS event (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE,\n"
+ " eventTypeId REFERENCES eventType,\n"
+ " entityId REFERENCES entity,\n"
+ " sourceEntityId REFERENCES entity DEFAULT NULL\n"
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS eventIndex ON event(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS eventIndex ON event(name);");
// create metric table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS metric (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS metric (\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL UNIQUE,\n"
+ " dimension TEXT NOT NULL\n"
+ ");");
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS metricIndex ON metric(name);");
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS metricIndex ON metric(name);");
// create entity metric instance value table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entityMetricInstanceValue (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entityMetricInstanceValue (\n"
+ " entityId REFERENCES entity(id),\n"
+ " metricId REFERENCES metric(id),\n"
+ " sqcnr INTEGER,\n"
+ " value TEXT,\n"
+ " PRIMARY KEY(entityId, metricId, sqcnr)\n"
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS entityMetricInstanceValueIndex ON entityMetricInstanceValue(entityId, metricId, sqcnr);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS entityMetricInstanceValueIndex ON entityMetricInstanceValue(entityId, metricId, sqcnr);");
// create entity instance metric value table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entityInstanceMetricValue (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entityInstanceMetricValue (\n"
+ " entityId ,\n"
+ " entityInstance ,\n"
+ " metricId REFERENCES metric(id),\n"
@@ -139,16 +118,16 @@
+ " PRIMARY KEY(entityId, entityInstance, metricId),\n"
+ " FOREIGN KEY(entityId, entityInstance) REFERENCES entityInstance\n"
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS entityInstanceMetricValueIndex ON entityInstanceMetricValue(entityId, entityInstance, metricId);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS entityInstanceMetricValueIndex ON entityInstanceMetricValue(entityId, entityInstance, metricId);");
// create entity metric value table and index
- this.statement.executeUpdate("CREATE TABLE IF NOT EXISTS entityMetricValue (\n"
+ this.connection.executeUpdate("CREATE TABLE IF NOT EXISTS entityMetricValue (\n"
+ " entityId REFERENCES entity(id),\n"
+ " metricId REFERENCES metric(id),\n"
+ " value TEXT,\n"
+ " PRIMARY KEY(entityId, metricId)\n"
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS entityMetricValueIndex ON entityMetricValue(entityId, metricId);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS entityMetricValueIndex ON entityMetricValue(entityId, metricId);");
return this;
}
@@ -158,7 +137,7 @@
+ " (SELECT name FROM %1$s WHERE id = %2$s.value)\n";
// human readable entity property values
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vPropertyValue AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vPropertyValue AS SELECT\n"
+ " (SELECT name FROM entity WHERE id = propertyValue.entityId) AS entityName,\n"
+ " (SELECT name FROM entityType WHERE id = "
+ "(SELECT entityTypeId FROM entity WHERE id = propertyValue.entityId)"
@@ -174,7 +153,7 @@
+ "FROM propertyValue GROUP BY entityId, propertyId ORDER BY entityId, propertyId;");
// human readable observable events
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEvent AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEvent AS SELECT\n"
+ " name,\n"
+ " (SELECT name FROM eventType WHERE id = eventTypeId) AS eventType,\n"
+ " (SELECT name FROM entity WHERE id = entityId) AS entityName,\n"
@@ -188,7 +167,7 @@
+ "FROM event;");
// human readable event chain table (extract from entity)
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEventChainEntity AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEventChainEntity AS SELECT\n"
+ " name AS eventChainName,\n"
+ " (SELECT GROUP_CONCAT(name, ', ') FROM event WHERE id IN (SELECT value FROM propertyValue WHERE"
+ " entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecStimulus'))) AS stimulus,\n"
@@ -203,7 +182,7 @@
+ "FROM entity AS ecEntity WHERE entityTypeId = (SELECT id FROM entityType WHERE entityType.name = 'EC');");
// human readable entity specific metric instances
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityMetricInstanceValue AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityMetricInstanceValue AS SELECT\n"
+ " (SELECT name FROM entity WHERE id = entityMetricInstanceValue.entityId) AS entityName,\n"
+ " (SELECT name FROM entityType WHERE id =\n"
+ " (SELECT entityTypeId FROM entity WHERE id = entityMetricInstanceValue.entityId)\n"
@@ -215,7 +194,7 @@
+ "ORDER BY entityId, metricId, sqcnr;");
// human readable entity instance specific metrics
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityInstanceMetricValue AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityInstanceMetricValue AS SELECT\n"
+ " (SELECT name FROM entity WHERE id = entityInstanceMetricValue.entityId) AS entityName,\n"
+ " (SELECT name FROM entityType WHERE id =\n"
+ " (SELECT entityTypeId FROM entity WHERE id = entityInstanceMetricValue.entityId)\n"
@@ -227,7 +206,7 @@
+ "ORDER BY entityId, entityInstance, metricId;");
// human readable entity specific metrics
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityMetricValue AS SELECT\n"
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEntityMetricValue AS SELECT\n"
+ " (SELECT name FROM entity WHERE id = entityMetricValue.entityId) AS entityName,\n"
+ " (SELECT name FROM entityType WHERE id =\n"
+ " (SELECT entityTypeId FROM entity WHERE id = entityMetricValue.entityId)\n"
@@ -246,11 +225,12 @@
private static String getInstRuntimeEventsQuery(final EntityType entityType) {
final String events = entityType.getPossibleEvents().stream().map(e -> "'" + e.toString().toLowerCase() + "'")
.collect(Collectors.joining(", "));
+ final String traceAliases = entityType.getTraceAliases().stream().map(ta -> "'" + ta + "'").collect(Collectors.joining(", "));
return " SELECT timestamp, sqcnr, entityId, entityInstance, sourceEntityId, sourceEntityInstance, eventTypeId\n"//
+ " FROM traceEvent WHERE\n"//
+ " eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + events + ")) AND\n"//
+ " entityId IN (SELECT id FROM entity WHERE entityTypeId IN\n"//
- + " (SELECT id FROM entityType WHERE name IN (" + entityType.getTraceAliases() + "))\n"//
+ + " (SELECT id FROM entityType WHERE name IN (" + traceAliases + "))\n"//
+ " )\n"//
+ " GROUP BY entityId, entityInstance, timestamp, sqcnr";
}
@@ -269,7 +249,7 @@
public ATDBBuilder createOptionalAndTemporaryTables(final Collection<? extends EntityType> entityTypes, final boolean persistOptionalTables) throws SQLException {
final String persistableTablePref = getPersistableTablePrefix(persistOptionalTables);
// create traceEvent table and indices
- this.statement.executeUpdate(persistableTablePref + "traceEvent (\n"
+ this.connection.executeUpdate(persistableTablePref + "traceEvent (\n"
+ " timestamp INTEGER,\n"
+ " sqcnr INTEGER,\n"
+ " entityId INTEGER,\n"
@@ -283,14 +263,14 @@
+ ",\n FOREIGN KEY(sourceEntityId, sourceEntityInstance) REFERENCES entityInstance"
+ ",\n FOREIGN KEY(eventTypeId) REFERENCES eventType\n" : "\n")
+ ");");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS traceEventIndex ON traceEvent(timestamp, sqcnr);");
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS traceEventIndexForECs ON traceEvent(entityId, eventTypeId);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS traceEventIndex ON traceEvent(timestamp, sqcnr);");
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS traceEventIndexForECs ON traceEvent(entityId, eventTypeId);");
createTemporaryEntityFilteredTraceEventTables(entityTypes);
for (final EntityType et : entityTypes) {
// extract runtime relevant traceEvent counts per entity instance
- this.statement.executeUpdate(persistableTablePref + et.getName() + "InstanceTraceInfo (\n"
+ this.connection.executeUpdate(persistableTablePref + et.getName() + "InstanceTraceInfo (\n"
+ " entityId INTEGER,\n"
+ " entityInstance INTEGER,\n"
+ et.getPossibleEvents().stream().map(e -> e.toString().toLowerCase() + "EventCount INTEGER,\n").collect(Collectors.joining())
@@ -298,12 +278,12 @@
+ " PRIMARY KEY(entityId, entityInstance)\n"
+ ");");
// create index for better performance on trace events
- this.statement.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS " + et.getName() + "InstanceTraceInfoIndex ON " + et.getName()
+ this.connection.executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS " + et.getName() + "InstanceTraceInfoIndex ON " + et.getName()
+ "InstanceTraceInfo(entityId, entityInstance);");
}
// create event chain info table
- this.statement.executeUpdate(persistableTablePref + "eventChainInstanceInfo (\n"//
+ this.connection.executeUpdate(persistableTablePref + "eventChainInstanceInfo (\n"//
+ " entityId INTEGER,\n"//
+ " entityInstance INTEGER,\n"//
+ " stimulusTimestamp INTEGER,\n"//
@@ -324,7 +304,7 @@
public ATDBBuilder createTemporaryEntityFilteredTraceEventTables(final Collection<? extends EntityType> entityTypes) throws SQLException {
for (final EntityType et : entityTypes) {
// collect/filter runtime relevant events per entity type
- this.statement.executeUpdate("CREATE TEMPORARY TABLE IF NOT EXISTS " + et.getName() + "InstanceRuntimeTraceEvent (\n"
+ this.connection.executeUpdate("CREATE TEMPORARY TABLE IF NOT EXISTS " + et.getName() + "InstanceRuntimeTraceEvent (\n"
+ " timestamp INTEGER,\n"
+ " sqcnr INTEGER,\n"
+ " entityId INTEGER,\n"
@@ -335,7 +315,7 @@
+ " PRIMARY KEY(timestamp, sqcnr)\n"
+ ");");
// create index for better performance on trace events
- this.statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + et.getName() + "InstanceRuntimeTraceEventIndex ON "
+ this.connection.executeUpdate("CREATE INDEX IF NOT EXISTS " + et.getName() + "InstanceRuntimeTraceEventIndex ON "
+ et.getName() + "InstanceRuntimeTraceEvent(entityId, entityInstance, eventTypeId);");
}
return this;
@@ -348,7 +328,7 @@
*/
public ATDBBuilder createOptionalViews(final Collection<? extends EntityType> entityTypes) throws SQLException {
// human readable event table
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vTraceEvent AS SELECT\n"//
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vTraceEvent AS SELECT\n"//
+ " traceEvent.timestamp,\n"//
+ " traceEvent.sqcnr,\n"//
+ " (SELECT name FROM entity WHERE id = traceEvent.entityId) AS entityName,\n"//
@@ -368,7 +348,7 @@
for (final EntityType et : entityTypes) {
final String reDBName = et.getName() + "InstanceRuntimeTraceEvent";
// human readable intermediate view for all runtime relevant events per entity instance
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS v" + reDBName + " AS SELECT\n"//
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS v" + reDBName + " AS SELECT\n"//
+ " timestamp,\n"//
+ " sqcnr,\n"//
+ " (SELECT name FROM entity WHERE id = entityId) AS " + et.getUCName() + "Name,\n"//
@@ -381,7 +361,7 @@
final String eiDBName = et.getName() + "InstanceTraceInfo";
final String eventCountColumns = et.getPossibleEvents().stream()
.map(ev -> eiDBName + "." + ev.toString().toLowerCase() + "EventCount").collect(Collectors.joining(",\n "));
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS v" + eiDBName + " AS SELECT\n"//
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS v" + eiDBName + " AS SELECT\n"//
+ " (SELECT name FROM entity WHERE id = " + eiDBName + ".entityId) AS " + et.getUCName() + "Name,\n"//
+ " " + eiDBName + ".entityInstance,\n"//
+ " " + eventCountColumns + ",\n"//
@@ -390,7 +370,7 @@
}
// human readable event chain instance info table
- this.statement.executeUpdate("CREATE VIEW IF NOT EXISTS vEventChainInstanceInfo AS SELECT\n"//
+ this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEventChainInstanceInfo AS SELECT\n"//
+ " (SELECT name FROM entity WHERE id = entityId) AS eventChainName,\n"//
+ " entityInstance AS ecInstance,\n"//
+ " stimulusTimestamp,\n"//
@@ -416,9 +396,9 @@
public void autoPopulateEntityFilteredTraceEventTables(final Collection<? extends EntityType> entityTypes) throws SQLException {
for (final EntityType et : entityTypes) {
// collect/filter runtime relevant events per entity instance
- this.statement.executeUpdate("INSERT INTO " + et.getName() + "InstanceRuntimeTraceEvent\n" + getInstRuntimeEventsQuery(et) + ";");
+ this.connection.executeUpdate("INSERT INTO " + et.getName() + "InstanceRuntimeTraceEvent\n" + getInstRuntimeEventsQuery(et) + ";");
// extract runtime relevant traceEvent counts per entity instance
- this.statement.executeUpdate("INSERT INTO " + et.getName() + "InstanceTraceInfo\n" + getInstEventInfosQuery(et) + ";");
+ this.connection.executeUpdate("INSERT INTO " + et.getName() + "InstanceTraceInfo\n" + getInstEventInfosQuery(et) + ";");
}
}
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java
new file mode 100644
index 0000000..c0dfcdd
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java
@@ -0,0 +1,102 @@
+package org.eclipse.app4mc.atdb;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Optional;
+import java.util.Properties;
+
+public final class ATDBConnection implements AutoCloseable {
+
+ private final Connection connection;
+ private final Optional<Statement> statement;
+
+ public ATDBConnection(final String atdbFile) throws SQLException {
+ this(atdbFile, false);
+ }
+
+ public ATDBConnection(final String atdbFile, final boolean writeAccess) throws SQLException {
+ try {
+ Class.forName("org.sqlite.JDBC"); // init JDBC driver
+ } catch (ClassNotFoundException e) {
+ // fail silently. DriverManager will throw an SQL exception complaining about a missing driver
+ }
+ final String dbFileUrl = "jdbc:sqlite:" + atdbFile;
+ if (!writeAccess) {
+ final Properties properties = new Properties();
+ properties.put("open_mode", "1"); //$NON-NLS-1$ //$NON-NLS-2$
+ this.connection = DriverManager.getConnection(dbFileUrl, properties);
+ this.statement = Optional.empty();
+ } else {
+ this.connection = DriverManager.getConnection(dbFileUrl);
+ final Statement statement = this.connection.createStatement();
+ statement.setQueryTimeout(30); // set timeout to 30 sec.
+ statement.executeUpdate("PRAGMA foreign_keys = ON;"); // enable foreign key checks
+ this.statement = Optional.of(statement);
+ }
+ }
+
+ @Override
+ public void close() throws SQLException {
+ if (this.statement.isPresent()) {
+ this.statement.get().close();
+ }
+ this.connection.close();
+ }
+
+ public boolean executeUpdate(final String query) throws SQLException {
+ if (this.statement.isPresent()) {
+ this.statement.get().execute(query);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @FunctionalInterface
+ public static interface ThrowingConsumer<T, E extends Exception> {
+ void accept(T t) throws E;
+ }
+
+ public void queryAndConsumeResult(final String query, final ThrowingConsumer<ResultSet, SQLException> consumer) throws SQLException {
+ try (final Statement statement = this.connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
+ final ResultSet resultSet = statement.executeQuery(query);
+ consumer.accept(resultSet);
+ }
+ }
+
+ @FunctionalInterface
+ public static interface ThrowingFunction<T, R, E extends Exception> {
+ R apply(T t) throws E;
+ }
+
+ public <R> R queryAndMapResult(final String query, final ThrowingFunction<ResultSet, R, SQLException> mapper) throws SQLException {
+ try (final Statement statement = this.connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
+ final ResultSet resultSet = statement.executeQuery(query);
+ return mapper.apply(resultSet);
+ }
+ }
+
+ public PreparedStatement prepareStatement(final String query) throws SQLException {
+ return this.connection.prepareStatement(query);
+ }
+
+ public Statement createStatement() throws SQLException {
+ return this.connection.createStatement();
+ }
+
+ public void executeBatchStatements(final Statement...statements) throws SQLException {
+ this.connection.setAutoCommit(false);
+ try {
+ for(final Statement stmt:statements) {
+ stmt.executeBatch();
+ }
+ } finally {
+ this.connection.setAutoCommit(true);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/EntityType.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/EntityType.java
index 7ff00da..059bbd7 100644
--- a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/EntityType.java
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/EntityType.java
@@ -13,9 +13,9 @@
return ucName;
}
- String getTraceAliases();
+ List<String> getTraceAliases();
- Set<? extends Enum<?>> getPossibleEvents();
+ Set<Enum<?>> getPossibleEvents();
List<String> getValidityConstraints();
}