mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1873 - Refactor metrics reporting and collection, simplify removing MetricOrmQueryNode, MetricOrmQueryOrigin (#1874)
* #1873 - Refactor metrics reporting and collection, simplify removing MetricOrmQueryNode, MetricOrmQueryOrigin * #1873 - fix test
This commit is contained in:
@@ -28,7 +28,6 @@ import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
@@ -415,10 +414,6 @@ public class ServerConfig {
|
||||
|
||||
private ServerCachePlugin serverCachePlugin;
|
||||
|
||||
private boolean collectQueryStatsByNode = true;
|
||||
|
||||
private boolean collectQueryOrigins = true;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
*/
|
||||
@@ -2418,52 +2413,6 @@ public class ServerConfig {
|
||||
this.updateAllPropertiesInBatch = updateAllPropertiesInBatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if query statistics should be collected by ObjectGraphNode.
|
||||
*/
|
||||
public boolean isCollectQueryStatsByNode() {
|
||||
return collectQueryStatsByNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to collection query execution statistics by ObjectGraphNode.
|
||||
* <p>
|
||||
* These statistics can be used to highlight code/query 'origin points' that result in lots of lazy loading.
|
||||
* </p>
|
||||
* <p>
|
||||
* It is considered safe/fine to have this set to true for production.
|
||||
* </p>
|
||||
* <p>
|
||||
* This information can be later retrieved via {@link MetaInfoManager}.
|
||||
* </p>
|
||||
*
|
||||
* @see MetaInfoManager
|
||||
*/
|
||||
public void setCollectQueryStatsByNode(boolean collectQueryStatsByNode) {
|
||||
this.collectQueryStatsByNode = collectQueryStatsByNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if query plans should also collect their 'origins'. This means for a given query plan you
|
||||
* can identify the code/origin points where this query resulted from including lazy loading origins.
|
||||
*/
|
||||
public boolean isCollectQueryOrigins() {
|
||||
return collectQueryOrigins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if query plans should collect their 'origin' points. This means for a given query plan you
|
||||
* can identify the code/origin points where this query resulted from including lazy loading origins.
|
||||
* <p>
|
||||
* This information can be later retrieved via {@link MetaInfoManager}.
|
||||
* </p>
|
||||
*
|
||||
* @see MetaInfoManager
|
||||
*/
|
||||
public void setCollectQueryOrigins(boolean collectQueryOrigins) {
|
||||
this.collectQueryOrigins = collectQueryOrigins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource directory.
|
||||
*/
|
||||
@@ -2921,9 +2870,6 @@ public class ServerConfig {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
packages = getSearchList(packagesProp, packages);
|
||||
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
|
||||
|
||||
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
|
||||
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@ import java.util.List;
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
|
||||
|
||||
private final List<MetaTimedMetric> timed = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
|
||||
private final List<MetaOrmQueryMetric> ormQuery = new ArrayList<>();
|
||||
private final List<MetaCountMetric> countMetrics = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> query = new ArrayList<>();
|
||||
private final List<MetaCountMetric> count = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct to reset and collect everything.
|
||||
@@ -27,33 +26,19 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaTimedMetric> getTimedMetrics() {
|
||||
return timed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaQueryMetric> getDtoQueryMetrics() {
|
||||
return dtoQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaOrmQueryMetric> getOrmQueryMetrics() {
|
||||
return ormQuery;
|
||||
public List<MetaQueryMetric> getQueryMetrics() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaCountMetric> getCountMetrics() {
|
||||
return countMetrics;
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,16 +48,11 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
|
||||
@Override
|
||||
public void visitQuery(MetaQueryMetric metric) {
|
||||
dtoQuery.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
ormQuery.add(metric);
|
||||
query.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
countMetrics.add(metric);
|
||||
count.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,16 +54,4 @@ public interface MetaInfoManager {
|
||||
*/
|
||||
void resetAllMetrics();
|
||||
|
||||
/**
|
||||
* Collect and return the ObjectGraphNode statistics.
|
||||
* <p>
|
||||
* These show query executions based on an origin point and relative path.
|
||||
* This is used to look at the amount of lazy loading occurring for a given
|
||||
* query origin point and highlight potential for tuning a query.
|
||||
* </p>
|
||||
*
|
||||
* @param reset Set to true to reset the underlying statistics after collection.
|
||||
*/
|
||||
List<MetaOrmQueryNode> collectNodeStatistics(boolean reset);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Query execution statistics for Orm queries.
|
||||
*/
|
||||
public interface MetaOrmQueryMetric extends MetaQueryMetric {
|
||||
|
||||
/**
|
||||
* Return true if this query plan was tuned by AutoTune.
|
||||
*/
|
||||
boolean isAutoTuned();
|
||||
|
||||
/**
|
||||
* Return the time of the last query executed using this plan.
|
||||
*/
|
||||
long getLastQueryTime();
|
||||
|
||||
/**
|
||||
* Return the 'origin' points and paths that resulted in the query being
|
||||
* executed and the associated number of times the query was executed via that
|
||||
* path.
|
||||
* <p>
|
||||
* This includes direct and lazy loading paths.
|
||||
* </p>
|
||||
*/
|
||||
List<MetaOrmQueryOrigin> getOrigins();
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
/**
|
||||
* Statistics for query execution based on object graph origin and paths.
|
||||
* <p>
|
||||
* These statistics can be used to identify origin queries that result in lots
|
||||
* of lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface MetaOrmQueryNode {
|
||||
|
||||
/**
|
||||
* Return the ObjectGraphNode which has the origin point and relative path.
|
||||
*/
|
||||
ObjectGraphNode getNode();
|
||||
|
||||
/**
|
||||
* Return the startTime of statistics collection.
|
||||
*/
|
||||
long getStartTime();
|
||||
|
||||
/**
|
||||
* Return the total count of queries executed for this node.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
/**
|
||||
* Return the total time of queries executed for this node.
|
||||
*/
|
||||
long getTotalTime();
|
||||
|
||||
/**
|
||||
* Return the total beans loaded by queries for this node.
|
||||
*/
|
||||
long getTotalBeans();
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
/**
|
||||
* Holds a query 'origin' point and count for the number of queries executed for
|
||||
* this 'origin'.
|
||||
* <p>
|
||||
* This basically points to the bit of original code and query that results in
|
||||
* this query directly or via lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface MetaOrmQueryOrigin {
|
||||
|
||||
/**
|
||||
* The 'origin' and path which this query belongs to.
|
||||
* <p>
|
||||
* For lazy loading queries this points to the original query and associated
|
||||
* navigation path that resulted in this query being executed.
|
||||
* </p>
|
||||
*/
|
||||
ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
/**
|
||||
* The number of times a query was fired for this node since the counter was
|
||||
* last reset.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
}
|
||||
@@ -40,11 +40,6 @@ public interface MetricVisitor {
|
||||
*/
|
||||
void visitQuery(MetaQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit ORM query metrics.
|
||||
*/
|
||||
void visitOrmQuery(MetaOrmQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit a Counter metric.
|
||||
*/
|
||||
|
||||
@@ -13,14 +13,9 @@ public interface ServerMetrics {
|
||||
List<MetaTimedMetric> getTimedMetrics();
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
* Return the query metrics.
|
||||
*/
|
||||
List<MetaQueryMetric> getDtoQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
List<MetaOrmQueryMetric> getOrmQueryMetrics();
|
||||
List<MetaQueryMetric> getQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the Counter metrics.
|
||||
|
||||
@@ -49,11 +49,6 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
*/
|
||||
void shutdownManaged();
|
||||
|
||||
/**
|
||||
* Return true if query origins should be collected.
|
||||
*/
|
||||
boolean isCollectQueryOrigins();
|
||||
|
||||
/**
|
||||
* Return true if updates in JDBC batch should include all columns if unspecified on the transaction.
|
||||
*/
|
||||
@@ -201,11 +196,6 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
*/
|
||||
boolean isSupportedType(java.lang.reflect.Type genericType);
|
||||
|
||||
/**
|
||||
* Collect query statistics by ObjectGraphNode. Used for Lazy loading reporting.
|
||||
*/
|
||||
void collectQueryStats(ObjectGraphNode objectGraphNode, long loadedBeanCount, long timeMicros);
|
||||
|
||||
/**
|
||||
* Return the ReadAuditLogger to use for logging all read audit events.
|
||||
*/
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.meta.MetaOrmQueryNode;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* Helper to collect the query execution statistics for a given node.
|
||||
*/
|
||||
public class CObjectGraphNodeStatistics {
|
||||
|
||||
private final ObjectGraphNode node;
|
||||
|
||||
private final LongAdder count = new LongAdder();
|
||||
|
||||
private final LongAdder totalTime = new LongAdder();
|
||||
|
||||
private final LongAdder totalBeans = new LongAdder();
|
||||
|
||||
private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
|
||||
|
||||
CObjectGraphNodeStatistics(ObjectGraphNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return count.sum() == 0;
|
||||
}
|
||||
|
||||
public void add(long beanCount, long exeMicros) {
|
||||
count.increment();
|
||||
totalTime.add(exeMicros);
|
||||
totalBeans.add(beanCount);
|
||||
}
|
||||
|
||||
public MetaOrmQueryNode get(boolean reset) {
|
||||
if (reset) {
|
||||
return new Snapshot(node, startTime.getAndSet(System.currentTimeMillis()), count.sumThenReset(),
|
||||
totalTime.sumThenReset(), totalBeans.sumThenReset());
|
||||
} else {
|
||||
return new Snapshot(node, startTime.get(), count.sum(), totalTime.sum(), totalBeans.sum());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Snapshot implements MetaOrmQueryNode {
|
||||
|
||||
private final ObjectGraphNode node;
|
||||
private final long startTime;
|
||||
private final long count;
|
||||
private final long totalTime;
|
||||
private final long totalBeans;
|
||||
|
||||
public Snapshot(ObjectGraphNode node, long startTime, long count, long totalTime, long totalBeans) {
|
||||
this.node = node;
|
||||
this.startTime = startTime;
|
||||
this.count = count;
|
||||
this.totalTime = totalTime;
|
||||
this.totalBeans = totalBeans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node + " count[" + count + "] time[" + totalTime + "] beans[" + totalBeans + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBeans() {
|
||||
return totalBeans;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import io.ebean.meta.AbstractMetricVisitor;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaOrmQueryNode;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
@@ -15,7 +13,6 @@ import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.meta.ServerMetricsAsJson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -66,18 +63,6 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
server.visitMetrics(new ResetVisitor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaOrmQueryNode> collectNodeStatistics(boolean reset) {
|
||||
|
||||
List<MetaOrmQueryNode> list = new ArrayList<>();
|
||||
for (CObjectGraphNodeStatistics nodeStatistics : server.objectGraphStats.values()) {
|
||||
if (!nodeStatistics.isEmpty()) {
|
||||
list.add(nodeStatistics.get(reset));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that resets the statistics but doesn't collect them.
|
||||
*/
|
||||
@@ -97,11 +82,6 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
// ignore
|
||||
|
||||
@@ -240,19 +240,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final boolean updateAllPropertiesInBatch;
|
||||
|
||||
private final boolean collectQueryOrigins;
|
||||
|
||||
private final boolean collectQueryStatsByNode;
|
||||
|
||||
private final long slowQueryMicros;
|
||||
|
||||
private final SlowQueryListener slowQueryListener;
|
||||
|
||||
/**
|
||||
* Cache used to collect statistics based on ObjectGraphNode (used to highlight lazy loading origin points).
|
||||
*/
|
||||
protected final ConcurrentHashMap<ObjectGraphNode, CObjectGraphNodeStatistics> objectGraphStats;
|
||||
|
||||
/**
|
||||
* Create the DefaultServer.
|
||||
*/
|
||||
@@ -261,7 +252,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
this.logManager = config.getLogManager();
|
||||
this.dtoBeanManager = config.getDtoBeanManager();
|
||||
this.serverConfig = config.getServerConfig();
|
||||
this.objectGraphStats = new ConcurrentHashMap<>();
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
this.serverCacheManager = cache;
|
||||
this.databasePlatform = config.getDatabasePlatform();
|
||||
@@ -282,8 +272,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
|
||||
this.updateAllPropertiesInBatch = serverConfig.isUpdateAllPropertiesInBatch();
|
||||
this.collectQueryOrigins = serverConfig.isCollectQueryOrigins();
|
||||
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
|
||||
this.callStackFactory = initCallStackFactory(serverConfig);
|
||||
|
||||
this.persister = config.createPersister(this);
|
||||
@@ -352,11 +340,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return logManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectQueryOrigins() {
|
||||
return collectQueryOrigins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdateAllPropertiesInBatch() {
|
||||
return updateAllPropertiesInBatch;
|
||||
@@ -2357,21 +2340,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return jsonContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
|
||||
|
||||
if (collectQueryStatsByNode) {
|
||||
CObjectGraphNodeStatistics nodeStatistics = objectGraphStats.get(node);
|
||||
if (nodeStatistics == null) {
|
||||
// race condition here but I actually don't care too much if we miss a
|
||||
// few early statistics - especially when the server is warming up etc
|
||||
nodeStatistics = new CObjectGraphNodeStatistics(node);
|
||||
objectGraphStats.put(node, nodeStatistics);
|
||||
}
|
||||
nodeStatistics.add(loadedBeanCount, timeMicros);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
|
||||
if (timeMicros > slowQueryMicros && slowQueryListener != null) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
@@ -92,23 +91,14 @@ class DumpMetrics {
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
if (!ormQueryMetrics.isEmpty()) {
|
||||
out("\n-- ORM queries --");
|
||||
ormQueryMetrics.sort(sortBy);
|
||||
for (MetaOrmQueryMetric metric : ormQueryMetrics) {
|
||||
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
if (!queryMetrics.isEmpty()) {
|
||||
out("\n-- Queries --");
|
||||
queryMetrics.sort(sortBy);
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaQueryMetric> dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
|
||||
if (!dtoQueryMetrics.isEmpty()) {
|
||||
out("\n-- DTO queries --");
|
||||
dtoQueryMetrics.sort(sortBy);
|
||||
for (MetaQueryMetric metric : dtoQueryMetrics) {
|
||||
logDtoQuery(metric);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logCount(MetaCountMetric metric) {
|
||||
@@ -123,7 +113,7 @@ class DumpMetrics {
|
||||
System.out.println(sb);
|
||||
}
|
||||
|
||||
private void logQuery(MetaOrmQueryMetric metric) {
|
||||
private void logQuery(MetaQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -136,17 +126,6 @@ class DumpMetrics {
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
private void logDtoQuery(MetaQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
appendQueryName(metric, sb);
|
||||
appendCounters(metric, sb);
|
||||
appendProfileAndSql(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
private void appendQueryName(MetaQueryMetric metric, StringBuilder sb) {
|
||||
sb.append("query:").append(padName(metric.getName())).append(" ");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.core;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaMetric;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricData;
|
||||
@@ -34,8 +33,7 @@ class DumpMetricsData {
|
||||
|
||||
final List<MetaTimedMetric> timedMetrics = serverMetrics.getTimedMetrics();
|
||||
final List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
|
||||
final List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
final List<MetaQueryMetric> dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
|
||||
final List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
|
||||
for (MetaTimedMetric metric : timedMetrics) {
|
||||
add(metric);
|
||||
@@ -43,12 +41,9 @@ class DumpMetricsData {
|
||||
for (MetaCountMetric metric : countMetrics) {
|
||||
addCount(metric);
|
||||
}
|
||||
for (MetaOrmQueryMetric metric : ormQueryMetrics) {
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
addQuery(metric);
|
||||
}
|
||||
for (MetaQueryMetric metric : dtoQueryMetrics) {
|
||||
addDtoQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
private MetricData create(MetaMetric metric) {
|
||||
@@ -68,19 +63,13 @@ class DumpMetricsData {
|
||||
data.setCount(metric.getCount());
|
||||
}
|
||||
|
||||
private void addQuery(MetaOrmQueryMetric metric) {
|
||||
private void addQuery(MetaQueryMetric metric) {
|
||||
final MetricData data = create(metric);
|
||||
appendCounters(data, metric);
|
||||
appendLocationAndSql(data, metric);
|
||||
data.setHash(metric.getHash());
|
||||
}
|
||||
|
||||
private void addDtoQuery(MetaQueryMetric metric) {
|
||||
final MetricData data = create(metric);
|
||||
appendCounters(data, metric);
|
||||
appendLocationAndSql(data, metric);
|
||||
}
|
||||
|
||||
private void appendLocationAndSql(MetricData data, MetaQueryMetric metric) {
|
||||
data.setLoc(metric.getLocation());
|
||||
data.setSql(metric.getSql());
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.core;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaMetric;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
@@ -110,25 +109,16 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
if (!ormQueryMetrics.isEmpty()) {
|
||||
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
if (!queryMetrics.isEmpty()) {
|
||||
if (sortBy != null) {
|
||||
ormQueryMetrics.sort(sortBy);
|
||||
queryMetrics.sort(sortBy);
|
||||
}
|
||||
for (MetaOrmQueryMetric metric : ormQueryMetrics) {
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaQueryMetric> dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
|
||||
if (!dtoQueryMetrics.isEmpty()) {
|
||||
if (sortBy != null) {
|
||||
dtoQueryMetrics.sort(sortBy);
|
||||
}
|
||||
for (MetaQueryMetric metric : dtoQueryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
end();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error writing metrics as JSON", e);
|
||||
|
||||
@@ -1697,7 +1697,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
iudMetrics.visit(visitor);
|
||||
for (CQueryPlan queryPlan : queryPlanCache.values()) {
|
||||
if (!queryPlan.isEmptyStats()) {
|
||||
visitor.visitOrmQuery(queryPlan.getSnapshot(visitor.isReset()));
|
||||
visitor.visitQuery(queryPlan.getSnapshot(visitor.isReset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
if (autoTuneProfiling) {
|
||||
profilingListener.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
}
|
||||
if (queryPlan.executionTime(loadedBeanCount, executionTimeMicros, objectGraphNode)) {
|
||||
if (queryPlan.executionTime(loadedBeanCount, executionTimeMicros)) {
|
||||
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
|
||||
}
|
||||
getTransaction().profileEvent(this);
|
||||
|
||||
@@ -117,7 +117,7 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros, null)) {
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros)) {
|
||||
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
|
||||
}
|
||||
getTransaction().profileEvent(this);
|
||||
|
||||
@@ -123,7 +123,7 @@ public class CQueryPlan {
|
||||
this.rawSql = rawSql;
|
||||
this.logWhereSql = logWhereSql;
|
||||
this.encryptedProps = sqlTree.getEncryptedProps();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.stats = new CQueryPlanStats(this);
|
||||
this.dependentTables = sqlTree.dependentTables();
|
||||
this.bindCapture = initBindCapture(server.getServerConfig(), query);
|
||||
this.hash = md5Hash();
|
||||
@@ -151,7 +151,7 @@ public class CQueryPlan {
|
||||
this.rowNumberIncluded = rowNumberIncluded;
|
||||
this.logWhereSql = logWhereSql;
|
||||
this.encryptedProps = sqlTree.getEncryptedProps();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.stats = new CQueryPlanStats(this);
|
||||
this.dependentTables = sqlTree.dependentTables();
|
||||
this.bindCapture = initBindCapture(server.getServerConfig(), query);
|
||||
this.hash = md5Hash();
|
||||
@@ -312,14 +312,8 @@ public class CQueryPlan {
|
||||
/**
|
||||
* Register an execution time against this query plan;
|
||||
*/
|
||||
boolean executionTime(long loadedBeanCount, long timeMicros, ObjectGraphNode objectGraphNode) {
|
||||
|
||||
stats.add(loadedBeanCount, timeMicros, objectGraphNode);
|
||||
if (objectGraphNode != null) {
|
||||
// collect stats based on objectGraphNode for lazy loading reporting
|
||||
server.collectQueryStats(objectGraphNode, loadedBeanCount, timeMicros);
|
||||
}
|
||||
|
||||
boolean executionTime(long loadedBeanCount, long timeMicros) {
|
||||
stats.add(loadedBeanCount, timeMicros);
|
||||
return bindCapture != null && bindCapture.collectFor(timeMicros);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaOrmQueryOrigin;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
import io.ebean.metric.TimedMetricStats;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* Statistics for a specific query plan that can accumulate.
|
||||
*/
|
||||
@@ -27,14 +18,11 @@ public final class CQueryPlanStats {
|
||||
|
||||
private long lastQueryTime;
|
||||
|
||||
private final ConcurrentHashMap<ObjectGraphNode, LongAdder> origins;
|
||||
|
||||
/**
|
||||
* Construct for a given query plan.
|
||||
*/
|
||||
CQueryPlanStats(CQueryPlan queryPlan, boolean collectQueryOrigins) {
|
||||
CQueryPlanStats(CQueryPlan queryPlan) {
|
||||
this.queryPlan = queryPlan;
|
||||
this.origins = !collectQueryOrigins ? null : new ConcurrentHashMap<>();
|
||||
this.timedMetric = queryPlan.createTimedMetric();
|
||||
}
|
||||
|
||||
@@ -48,25 +36,10 @@ public final class CQueryPlanStats {
|
||||
/**
|
||||
* Add a query execution to the statistics.
|
||||
*/
|
||||
public void add(long loadedBeanCount, long timeMicros, ObjectGraphNode objectGraphNode) {
|
||||
|
||||
public void add(long loadedBeanCount, long timeMicros) {
|
||||
timedMetric.add(timeMicros, loadedBeanCount);
|
||||
|
||||
// not safe but should be atomic
|
||||
lastQueryTime = System.currentTimeMillis();
|
||||
|
||||
if (origins != null && objectGraphNode != null) {
|
||||
// Maintain the origin points this query fires from
|
||||
// with a simple counter
|
||||
LongAdder counter = origins.get(objectGraphNode);
|
||||
if (counter == null) {
|
||||
// race condition - we can miss counters here but going
|
||||
// to live with that. Don't want to lock/synchronize etc
|
||||
counter = new LongAdder();
|
||||
origins.put(objectGraphNode, counter);
|
||||
}
|
||||
counter.increment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,11 +47,6 @@ public final class CQueryPlanStats {
|
||||
*/
|
||||
public void reset() {
|
||||
timedMetric.reset();
|
||||
if (origins != null) {
|
||||
for (LongAdder counter : origins.values()) {
|
||||
counter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,77 +62,24 @@ public final class CQueryPlanStats {
|
||||
Snapshot getSnapshot(boolean reset) {
|
||||
|
||||
TimedMetricStats collect = timedMetric.collect(reset);
|
||||
List<MetaOrmQueryOrigin> origins = getOrigins(reset);
|
||||
Snapshot snapshot = new Snapshot(collected, queryPlan, collect, lastQueryTime, origins);
|
||||
Snapshot snapshot = new Snapshot(collected, queryPlan, collect);
|
||||
collected = true;
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list/snapshot of the origins and their counter value.
|
||||
*/
|
||||
private List<MetaOrmQueryOrigin> getOrigins(boolean reset) {
|
||||
if (origins == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<MetaOrmQueryOrigin> list = new ArrayList<>(origins.size());
|
||||
|
||||
for (Entry<ObjectGraphNode, LongAdder> entry : origins.entrySet()) {
|
||||
if (reset) {
|
||||
list.add(new OriginSnapshot(entry.getKey(), entry.getValue().sumThenReset()));
|
||||
} else {
|
||||
list.add(new OriginSnapshot(entry.getKey(), entry.getValue().sum()));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Snapshot of the origin ObjectGraphNode and counter value.
|
||||
*/
|
||||
private static class OriginSnapshot implements MetaOrmQueryOrigin {
|
||||
private final ObjectGraphNode objectGraphNode;
|
||||
private final long count;
|
||||
|
||||
OriginSnapshot(ObjectGraphNode objectGraphNode, long count) {
|
||||
this.objectGraphNode = objectGraphNode;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "node[" + objectGraphNode + "] count[" + count + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getObjectGraphNode() {
|
||||
return objectGraphNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A snapshot of the current statistics for a query plan.
|
||||
*/
|
||||
static class Snapshot implements MetaOrmQueryMetric {
|
||||
static class Snapshot implements MetaQueryMetric {
|
||||
|
||||
private final boolean collected;
|
||||
private final CQueryPlan queryPlan;
|
||||
private final TimedMetricStats metrics;
|
||||
private final long lastQueryTime;
|
||||
private final List<MetaOrmQueryOrigin> origins;
|
||||
|
||||
Snapshot(boolean collected, CQueryPlan queryPlan, TimedMetricStats metrics, long lastQueryTime, List<MetaOrmQueryOrigin> origins) {
|
||||
Snapshot(boolean collected, CQueryPlan queryPlan, TimedMetricStats metrics) {
|
||||
this.collected = collected;
|
||||
this.queryPlan = queryPlan;
|
||||
this.metrics = metrics;
|
||||
this.lastQueryTime = lastQueryTime;
|
||||
this.origins = origins;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,16 +142,6 @@ public final class CQueryPlanStats {
|
||||
return metrics.getStartTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastQueryTime() {
|
||||
return lastQueryTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTuned() {
|
||||
return queryPlan.isAutoTuned();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHash() {
|
||||
return queryPlan.getHash();
|
||||
@@ -252,11 +157,6 @@ public final class CQueryPlanStats {
|
||||
return !collected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaOrmQueryOrigin> getOrigins() {
|
||||
return origins;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class CQueryRowCount implements SpiProfileTransactionEvent {
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros, query.getParentNode())) {
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros)) {
|
||||
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
|
||||
}
|
||||
t.profileEvent(this);
|
||||
|
||||
@@ -93,7 +93,7 @@ class CQueryUpdate implements SpiProfileTransactionEvent {
|
||||
|
||||
long executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros, null)) {
|
||||
if (queryPlan.executionTime(rowCount, executionTimeMicros)) {
|
||||
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
|
||||
}
|
||||
t.profileEvent(this);
|
||||
|
||||
Reference in New Issue
Block a user