283 lines
7.5 KiB
Java
283 lines
7.5 KiB
Java
/*
|
|
* (C) Copyright 2014, 2016, 2017 Hewlett Packard Enterprise Development LP
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
* in compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
package monasca.api.infrastructure.persistence.vertica;
|
|
|
|
import monasca.api.domain.model.metric.MetricDefinitionRepo;
|
|
import monasca.api.domain.model.metric.MetricName;
|
|
import monasca.api.resource.exception.Exceptions;
|
|
import monasca.api.ApiConfig;
|
|
import monasca.common.model.metric.MetricDefinition;
|
|
|
|
import org.apache.commons.codec.DecoderException;
|
|
import org.apache.commons.codec.binary.Hex;
|
|
import org.joda.time.DateTime;
|
|
import org.skife.jdbi.v2.DBI;
|
|
import org.skife.jdbi.v2.Handle;
|
|
import org.skife.jdbi.v2.Query;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import javax.inject.Inject;
|
|
import javax.inject.Named;
|
|
|
|
public class MetricDefinitionVerticaRepoImpl implements MetricDefinitionRepo {
|
|
|
|
private static final Logger
|
|
logger =
|
|
LoggerFactory.getLogger(MetricDefinitionVerticaRepoImpl.class);
|
|
|
|
private static final String METRIC_DEF_SUB_QUERY =
|
|
"SELECT TO_HEX(defDimsSub.id) "
|
|
+ "FROM MonMetrics.Definitions defSub "
|
|
+ "JOIN MonMetrics.DefinitionDimensions defDimsSub ON defSub.id = defDimsSub.definition_id "
|
|
+ "%s " // possible measurements time join here
|
|
+ "WHERE defSub.tenant_id = :tenantId "
|
|
+ "%s " // Name goes here
|
|
+ "%s " // Offset goes here
|
|
+ "%s " // Dimensions and clause goes here
|
|
+ "%s " // possible time and clause here
|
|
+ "GROUP BY defDimsSub.id "
|
|
+ "ORDER BY defDimsSub.id ASC "
|
|
+ "%s "; // limit goes here
|
|
|
|
private static final String FIND_METRIC_NAMES_SQL =
|
|
"SELECT %s distinct def.name "
|
|
+ "FROM MonMetrics.Definitions def "
|
|
+ "JOIN MonMetrics.DefinitionDimensions defDimsSub ON def.id = defDimsSub.definition_id "
|
|
+ "WHERE def.tenant_id = :tenantId " // tenantId
|
|
+ "%s " // Offset goes here
|
|
+ "%s " // Dimensions and clause goes here
|
|
+ "ORDER BY def.name ASC "
|
|
+ "%s "; // Limit goes here.
|
|
|
|
private static final String TABLE_TO_JOIN_ON = "defDimsSub";
|
|
|
|
private final DBI db;
|
|
|
|
private final String dbHint;
|
|
|
|
@Inject
|
|
public MetricDefinitionVerticaRepoImpl(@Named("vertica") DBI db, ApiConfig config)
|
|
{
|
|
this.db = db;
|
|
this.dbHint = config.vertica.dbHint;
|
|
}
|
|
|
|
@Override
|
|
public List<MetricName> findNames(
|
|
String tenantId, Map<String,
|
|
String> dimensions,
|
|
String offset,
|
|
int limit) throws Exception {
|
|
|
|
List<Map<String, Object>> rows = executeMetricNamesQuery(tenantId, dimensions, offset, limit);
|
|
|
|
List<MetricName> metricNameList = new ArrayList<>(rows.size());
|
|
|
|
for (Map<String, Object> row : rows) {
|
|
|
|
String name = (String) row.get("name");
|
|
|
|
MetricName metricName = new MetricName(name);
|
|
|
|
metricNameList.add(metricName);
|
|
|
|
}
|
|
|
|
return metricNameList;
|
|
|
|
}
|
|
|
|
private List<Map<String, Object>> executeMetricNamesQuery(
|
|
String tenantId,
|
|
Map<String, String> dimensions,
|
|
String offset,
|
|
int limit) {
|
|
|
|
String offsetPart = "";
|
|
|
|
if (offset != null && !offset.isEmpty()) {
|
|
|
|
offsetPart = " and def.name > '" + offset + "' ";
|
|
|
|
}
|
|
|
|
// Can't bind limit in a nested sub query. So, just tack on as String.
|
|
String limitPart = " limit " + Integer.toString(limit + 1);
|
|
|
|
try (Handle h = db.open()) {
|
|
String sql = String.format(
|
|
FIND_METRIC_NAMES_SQL,
|
|
this.dbHint,
|
|
offsetPart,
|
|
MetricQueries.buildDimensionAndClause(dimensions, TABLE_TO_JOIN_ON),
|
|
limitPart);
|
|
|
|
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
|
|
|
MetricQueries.bindDimensionsToQuery(query, dimensions);
|
|
|
|
return query.list();
|
|
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<MetricDefinition> find(
|
|
String tenantId,
|
|
String name,
|
|
Map<String, String> dimensions,
|
|
DateTime startTime,
|
|
DateTime endTime,
|
|
String offset,
|
|
int limit) {
|
|
|
|
List<Map<String, Object>>
|
|
rows =
|
|
executeMetricDefsQuery(tenantId, name, dimensions, startTime, endTime, offset, limit);
|
|
|
|
List<MetricDefinition> metricDefs = new ArrayList<>(rows.size());
|
|
|
|
String currentDefDimId = null;
|
|
|
|
Map<String, String> dims = null;
|
|
|
|
for (Map<String, Object> row : rows) {
|
|
|
|
String defDimId = (String) row.get("defDimsId");
|
|
|
|
String metricName = (String) row.get("name");
|
|
|
|
String dimName = (String) row.get("dName");
|
|
|
|
String dimValue = (String) row.get("dValue");
|
|
|
|
if (defDimId == null || !defDimId.equals(currentDefDimId)) {
|
|
|
|
currentDefDimId = defDimId;
|
|
|
|
dims = new HashMap<>();
|
|
|
|
if (dimName != null && dimValue != null) {
|
|
|
|
dims.put(dimName, dimValue);
|
|
|
|
}
|
|
|
|
MetricDefinition m = new MetricDefinition(metricName, dims);
|
|
m.setId(defDimId);
|
|
metricDefs.add(m);
|
|
|
|
|
|
} else {
|
|
|
|
dims.put(dimName, dimValue);
|
|
|
|
}
|
|
}
|
|
|
|
return metricDefs;
|
|
}
|
|
|
|
private List<Map<String, Object>> executeMetricDefsQuery(
|
|
String tenantId,
|
|
String name,
|
|
Map<String, String> dimensions,
|
|
DateTime startTime,
|
|
DateTime endTime,
|
|
String offset,
|
|
int limit) {
|
|
|
|
String namePart = "";
|
|
|
|
if (name != null && !name.isEmpty()) {
|
|
|
|
namePart = " and defSub.name = :name ";
|
|
|
|
}
|
|
|
|
String offsetPart = "";
|
|
|
|
if (offset != null && !offset.isEmpty()) {
|
|
|
|
offsetPart = " and defDimsSub.id > :offset ";
|
|
|
|
}
|
|
|
|
String limitPart = "";
|
|
|
|
if (limit > 0) {
|
|
|
|
limitPart = "limit " + Integer.toString(limit + 1);
|
|
|
|
}
|
|
|
|
try (Handle h = db.open()) {
|
|
|
|
String sql =
|
|
String.format(MetricQueries.FIND_METRIC_DEFS_SQL,
|
|
this.dbHint,
|
|
String.format(METRIC_DEF_SUB_QUERY,
|
|
MetricQueries.buildTimeJoin(startTime),
|
|
namePart,
|
|
offsetPart,
|
|
MetricQueries.buildDimensionAndClause(dimensions,
|
|
TABLE_TO_JOIN_ON),
|
|
MetricQueries.buildTimeAndClause(startTime, endTime),
|
|
limitPart)
|
|
);
|
|
|
|
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
|
|
|
if (name != null && !name.isEmpty()) {
|
|
logger.debug("binding name: {}", name);
|
|
query.bind("name", name);
|
|
}
|
|
|
|
if (startTime != null) {
|
|
query.bind("startTime", startTime);
|
|
}
|
|
|
|
if (endTime != null) {
|
|
query.bind("endTime", endTime);
|
|
}
|
|
|
|
if (offset != null && !offset.isEmpty()) {
|
|
|
|
logger.debug("binding offset: {}", offset);
|
|
|
|
try {
|
|
|
|
query.bind("offset", Hex.decodeHex(offset.toCharArray()));
|
|
|
|
} catch (DecoderException e) {
|
|
|
|
throw Exceptions.badRequest("failed to decode offset " + offset, e);
|
|
}
|
|
|
|
}
|
|
|
|
MetricQueries.bindDimensionsToQuery(query, dimensions);
|
|
|
|
return query.list();
|
|
|
|
}
|
|
}
|
|
}
|