blob: 010c534eb6f5468ae0a055acec4dee3b51fdd7bc [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2020 Eclipse APP4MC contributors.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************
*/
package org.eclipse.app4mc.atdb.metrics;
import java.sql.SQLException;
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.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.app4mc.atdb.MetricAggregation;
import org.eclipse.core.resources.IFile;
public class DatabaseAccess implements AutoCloseable {
private final ATDBConnection traceDbConnection;
private final String timeBase;
private final Map<String, DBResultRowDataProvider> query2Result;
private static class PrependedColumn {
private final String entityIdStr;
private final boolean orderedEntityIdStr;
private final String entityId2Query;
private final String entityId2Name;
private PrependedColumn(final String entityIdStr, final boolean ordered, final String entityId2Query, final String entityId2Name) {
this.entityIdStr = entityIdStr;
this.orderedEntityIdStr = ordered;
this.entityId2Query = entityId2Query;
this.entityId2Name = entityId2Name;
}
}
private static String getPrependedColumnsEntityIdStr(final List<PrependedColumn> prependedColumns) {
return (prependedColumns.isEmpty() ? "" : prependedColumns.stream().map(c -> c.entityIdStr).collect(Collectors.joining(", ")) + ", ");
}
private static String getPrependedColumns2Order(final List<PrependedColumn> prependedColumns) {
String result = prependedColumns.stream().map(c -> c.orderedEntityIdStr ? c.entityIdStr : "").filter(s -> s.length() > 0)
.collect(Collectors.joining(", "));
if (result.length() > 0) result += ", ";
return result;
}
private static String getPrependedColumnsEntityId2Query(final List<PrependedColumn> prependedColumns, final String indent) {
return prependedColumns.isEmpty() ? "" : indent + prependedColumns.stream().map(c -> c.entityId2Query).collect(Collectors.joining(",\n" + indent)) + ",\n";
}
private static String getPrependedColumnsEntityId2Name(final List<PrependedColumn> prependedColumns, final String indent) {
return prependedColumns.isEmpty() ? "" : indent + prependedColumns.stream().map(c -> c.entityId2Name).collect(Collectors.joining(",\n" + indent)) + ",\n";
}
public DatabaseAccess(final IFile databaseFile) throws SQLException {
this.traceDbConnection = new ATDBConnection(databaseFile.getLocation().toFile().toString());
this.timeBase = this.traceDbConnection.getTimeBase();
this.query2Result = new LinkedHashMap<>();
}
@Override
public void close() throws SQLException {
this.query2Result.clear();
this.traceDbConnection.close();
}
public DBResultRowDataProvider getProcessMetricValues(final List<String> metricDimensions, final boolean groupByProcess) throws SQLException {
return getMetricValues(Arrays.asList("T", "I"), metricDimensions, Collections.emptyList(), Messages.DBViewer_processTitle,
groupByProcess ? Arrays.asList(0): Collections.emptyList());
}
public DBResultRowDataProvider getRunnableMetricValues(final List<String> metricDimensions, final boolean showAndGroupByProcess,
final boolean groupByRunnable) throws SQLException {
final List<PrependedColumn> prependColumns = new ArrayList<>();
if (showAndGroupByProcess) {
prependColumns.add(new PrependedColumn(
Messages.DBViewer_processTitle.toLowerCase() + "Id",
true,
" (SELECT entityId FROM propertyValue\n"
+ " WHERE propertyId = (SELECT id FROM property WHERE name = 'runnables') AND\n"
+ " CAST(propertyValue.value AS INTEGER) = entityInstanceMetricValue.entityId)",
"(SELECT name FROM entity WHERE id = " + Messages.DBViewer_processTitle.toLowerCase() + "Id) AS '" + Messages.DBViewer_processTitle + " "
+ Messages.DBViewer_nameTitle + "'"));
}
final List<Integer> groupColumnIndices = new ArrayList<>();
if (showAndGroupByProcess || groupByRunnable) groupColumnIndices.add(0);
if (showAndGroupByProcess && groupByRunnable) groupColumnIndices.add(1);
return getMetricValues(Arrays.asList("R"), metricDimensions, prependColumns, Messages.DBViewer_runnableTitle, groupColumnIndices);
}
public DBResultRowDataProvider getEventChainMetricValues(final List<String> metricDimensions) throws SQLException {
return getMetricValues(Arrays.asList("EC"), metricDimensions, Collections.emptyList(), Messages.DBViewer_eventChainTitle,
Collections.emptyList());
}
private DBResultRowDataProvider getMetricValues(final List<String> entityTypes, final List<String> metricDimensions,
final List<PrependedColumn> prependColumns, final String entityTypeLabel, final List<Integer> groupColumnIndices)
throws SQLException {
final String entityTypesFilter = entityTypes.isEmpty() ? "": " WHERE entityTypeId IN (SELECT id FROM entityType WHERE name IN ("
+ entityTypes.stream().map(et -> "'" + et + "'").collect(Collectors.joining(", ")) + "))"; //$NON-NLS-1$
final String metricDimensionsFilter = metricDimensions.isEmpty() ? "": " WHERE dimension IN ("
+ metricDimensions.stream().map(md -> "'" + md + "'").collect(Collectors.joining(", ")) + ")"; //$NON-NLS-1$
final String queryString = "WITH\n"
+ " entitiesToConsider(id) AS (SELECT id FROM entity" + entityTypesFilter + "),\n"
+ " metricsToConsider(id) AS (SELECT id FROM metric" + metricDimensionsFilter + "),\n"
+ " precalculated(" + getPrependedColumnsEntityIdStr(prependColumns)
+ entityTypeLabel.toLowerCase() + "Id, metricId, " + Stream.of(MetricAggregation.values())
.map(ma -> ma.getSQLLabel()).collect(Collectors.joining(", ")) + ") AS (SELECT\n"
+ getPrependedColumnsEntityId2Query(prependColumns, " ")
+ " entityInstanceMetricValue.entityId,\n"
+ " entityInstanceMetricValue.metricId,\n"
+ Stream.of(MetricAggregation.values()).map(ma -> " " + ma.getSQLStr("entityInstanceMetricValue.value"))
.collect(Collectors.joining(",\n")) + "\n"
+ " FROM entityInstanceMetricValue\n"
+ " WHERE entityId IN (SELECT id FROM entitiesToConsider) AND\n"
+ " metricId IN (SELECT id FROM metricsToConsider)\n"
+ " GROUP BY entityId, metricId)\n\n"
+ "SELECT\n"
+ getPrependedColumnsEntityId2Name(prependColumns, " ")
+ " (SELECT name FROM entity WHERE id = " + entityTypeLabel.toLowerCase() + "Id) AS '" + entityTypeLabel + " "
+ Messages.DBViewer_nameTitle + "',\n"
+ " (SELECT name FROM metric WHERE id = metricId) AS '" + Messages.DBViewer_metricColumnTitle + "',\n"
+ Stream.of(MetricAggregation.values()).map(ma -> " " + ma.getSQLLabel() + " AS '" + ma.getUILabel() + " [" + timeBase + "]'")
.collect(Collectors.joining(",\n")) + "\n"
+ "FROM precalculated\n"
+ "ORDER BY " + getPrependedColumns2Order(prependColumns) + entityTypeLabel.toLowerCase() + "Id, metricId;"; //$NON-NLS-1$
if (!this.query2Result.containsKey(queryString)) {
this.traceDbConnection.queryAndConsumeResult(queryString, rs ->
this.query2Result.put(queryString, DBResultRowDataProvider.of(rs, groupColumnIndices)));
}
return this.query2Result.get(queryString);
}
}