| /** |
| ******************************************************************************** |
| * 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); |
| } |
| } |