package org.spotter.ext.detection.edc.utils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.aim.api.measurement.AbstractRecord;
import org.aim.api.measurement.dataset.Dataset;
import org.aim.api.measurement.dataset.ParameterSelection;
import org.aim.artifacts.records.ResponseTimeRecord;
import org.aim.artifacts.records.SQLQueryRecord;
import org.aim.artifacts.records.StackTraceRecord;
import org.aim.artifacts.records.ThreadTracingRecord;
import org.lpe.common.util.NumericPair;
import org.lpe.common.util.NumericPairList;
public class DataAnalyzationUtils {
private DataAnalyzationUtils() {
}
/**
* Generates a NumericPairList of the response times of the given servlet.
*
* @param servlet
* servlet to get the response times of
* @param responseTimes
* dataset of all response times
* @return a NumericPairList of the response times of the given servlet
*/
public static NumericPairList<Long, Long> getServletResponseTimesOverTime(String servlet, Dataset responseTimes) {
NumericPairList<Long, Long> rtList = new NumericPairList<>();
Dataset thisServletsRTs = selectRTOperation(servlet).applyTo(responseTimes);
if (thisServletsRTs == null) {
return rtList;
}
for (ResponseTimeRecord rtRec : thisServletsRTs.getRecords(ResponseTimeRecord.class)) {
rtList.add(new NumericPair<Long, Long>(rtRec.getTimeStamp(), rtRec.getResponseTime()));
}
return rtList;
}
/**
* Generates a NumericPairList of the response times of the given query.
*
* @param query
* query to get the response times of
* @param responseTimes
* dataset of all response times
* @param queries
* dataset of all queries
* @return a NumericPairList of the response times of the given query
*/
public static NumericPairList<Long, Long> getQueryResponseTimesOverTime(String query, Dataset responseTimes,
Dataset queries) {
NumericPairList<Long, Long> rtList = new NumericPairList<>();
Dataset thisQueryRecords = new ParameterSelection().select(SQLQueryRecord.PAR_QUERY_STRING, query).applyTo(
queries);
if (thisQueryRecords == null) {
return rtList;
}
for (SQLQueryRecord sqlRec : thisQueryRecords.getRecords(SQLQueryRecord.class)) {
Dataset rtDs = selectCallID(sqlRec.getCallId()).applyTo(responseTimes);
if (rtDs == null) {
return rtList;
}
for (ResponseTimeRecord rtRec : rtDs.getRecords(ResponseTimeRecord.class)) {
rtList.add(new NumericPair<Long, Long>(rtRec.getTimeStamp(), rtRec.getResponseTime()));
}
}
return rtList;
}
/**
* Extracts the unique operation names in the given dataset.
*
* @param responseTimes
* dataset to retrieve the operation names from
* @return unique operation names in the given dataset
*/
public static Set<String> extractUniqueMethodNames(Dataset responseTimes) {
Set<String> uniqueNames = new TreeSet<>();
for (ResponseTimeRecord rtRecord : responseTimes.getRecords(ResponseTimeRecord.class)) {
if (!rtRecord.getOperation().startsWith("org.apache")) {
uniqueNames.add(rtRecord.getOperation());
}
}
return uniqueNames;
}
/**
* Generates a MethodCallSet only taking into account the given method
* names.
*
* @param methodNames
* method names to take into account
* @param responseTimes
* dataset of all response times
* @param threadTracing
* dataset of all thread tracing
* @return a MethodCallSet only taking into account the given method names
*/
public static MethodCallSet getMethodCallSetOfMethods(Set<String> methodNames, Dataset responseTimes,
Dataset threadTracing) {
long min = Long.MAX_VALUE;
long max = Long.MIN_VALUE;
long numRecords = 0;
for (ResponseTimeRecord rtRec : responseTimes.getRecords(ResponseTimeRecord.class)) {
if (rtRec.getTimeStamp() < min) {
min = rtRec.getTimeStamp();
}
if (rtRec.getTimeStamp() + rtRec.getResponseTime() > max) {
max = rtRec.getTimeStamp() + rtRec.getResponseTime();
}
numRecords++;
}
Set<Long> tids = new HashSet<>();
for (ThreadTracingRecord ttRec : threadTracing.getRecords(ThreadTracingRecord.class)) {
tids.add(ttRec.getThreadId());
}
MethodCallSet servletCallSet = new MethodCallSet(min, max, numRecords / tids.size());
for (ResponseTimeRecord rtRec : responseTimes.getRecords(ResponseTimeRecord.class)) {
if (methodNames.contains(rtRec.getOperation())) {
Dataset ttSet = selectCallID(rtRec.getCallId()).applyTo(threadTracing);
if (ttSet == null) {
continue;
}
long threadId = ttSet.getRecords(ThreadTracingRecord.class).get(0).getThreadId();
servletCallSet.addCall(new MethodCall(rtRec.getOperation(), rtRec.getTimeStamp(), rtRec.getTimeStamp()
+ rtRec.getResponseTime(), threadId));
}
}
return servletCallSet;
}
/**
* Inserts the given queries into the given MethodCallSet.
*
* @param set
* MethodCallSet to insert the queries
* @param responseTimes
* dataset of all response times
*
* @param queries
* dataset of all queries
* @param threadTracing
* dataset of all thread tracing
*/
public static void addQueriesToMethodCallSet(MethodCallSet set, Dataset responseTimes, Dataset queries,
Dataset threadTracing) {
for (SQLQueryRecord sqlRecord : queries.getRecords(SQLQueryRecord.class)) {
if (sqlRecord.getQueryString() == null) {
continue;
}
Dataset querySet = selectCallID(sqlRecord.getCallId()).applyTo(responseTimes);
if (querySet == null) {
continue;
}
ResponseTimeRecord rtRecord = querySet.getRecords(ResponseTimeRecord.class).get(0);
Dataset ttSet = selectCallID(sqlRecord.getCallId()).applyTo(threadTracing);
if (ttSet == null) {
continue;
}
ThreadTracingRecord ttRecord = ttSet.getRecords(ThreadTracingRecord.class).get(0);
set.addCallIfNested(new MethodCall(sqlRecord.getQueryString(), rtRecord.getTimeStamp(), rtRecord
.getTimeStamp() + rtRecord.getResponseTime(), ttRecord.getThreadId()));
}
}
/**
* Returns a ParameterSelection which selects the given call id.
*
* @param callId
* call id
* @return a ParameterSelection which selects the given call id
*/
private static ParameterSelection selectCallID(long callId) {
return new ParameterSelection().select(AbstractRecord.PAR_CALL_ID, callId);
}
/**
* Returns a ParameterSelection which selects the given operation.
*
* @param operation
* operation name
* @return a ParameterSelection which selects the given operation
*/
private static ParameterSelection selectRTOperation(String operation) {
return new ParameterSelection().select(ResponseTimeRecord.PAR_OPERATION, operation);
}
/**
* Returns all stack traces containing the given query.
*
* @param query
* query to get the stack traces from
* @param queries
* dataset of all queries
* @param stackTraces
* dataset of all stack traces
* @return all stack traces containing the given query
*/
public static Set<String> getStackTracesOfQuery(String query, Dataset queries, Dataset stackTraces) {
Set<String> stackTraceSet = new TreeSet<>();
ParameterSelection selectQuery = new ParameterSelection().select(SQLQueryRecord.PAR_QUERY_STRING, query);
List<SQLQueryRecord> queryRecords = selectQuery.applyTo(queries).getRecords(SQLQueryRecord.class);
for (SQLQueryRecord queryRecord : queryRecords) {
Dataset stSet = selectCallID(queryRecord.getCallId()).applyTo(stackTraces);
if (stSet == null) {
continue;
}
StackTraceRecord stackTraceRecord = stSet.getRecords(StackTraceRecord.class).get(0);
stackTraceSet.add(stackTraceRecord.getStackTrace());
}
return stackTraceSet;
}
/**
* Computes the relative response times (relative to the calling servlets)
* of the given query.
*
* @param query
* query to compute the relative response times from
* @param servletQueryHierarchy
* MethodCallSet
* @return the relative response times (relative to the calling servlets) of
* the given query
*/
public static List<Double> getRelativeQueryResponseTimes(String query, MethodCallSet servletQueryHierarchy) {
List<Double> relativeResponseTimes = new ArrayList<>();
for (MethodCall servletCall : servletQueryHierarchy.getMethodCalls()) {
for (MethodCall queryCall : servletCall.getCalledOperations()) {
if (queryCall.getOperation().equals(query)) {
relativeResponseTimes.add((double) queryCall.getResponseTime()
/ (double) servletCall.getResponseTime());
}
}
}
return relativeResponseTimes;
}
}