#1865 - ENH: Add metric collection for ORM insert update and delete

This commit is contained in:
rob bygrave
2019-11-19 20:27:04 +13:00
parent aa11095d17
commit 17ff04e2b9
14 changed files with 267 additions and 4 deletions
@@ -10,6 +10,11 @@ public enum MetricType {
*/
TXN,
/**
* ORM Insert Update or Delete.
*/
IUD,
/**
* ORM queries.
*/
@@ -17,6 +17,11 @@ public interface TimedMetric {
*/
void add(long micros, long beans);
/**
* Add a time event for a batch of beans.
*/
void addBatchSince(long startNanos, int batch);
/**
* Add a time event given the start nanos.
*/
@@ -57,6 +57,15 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
this.label = label;
}
@Override
public void addTimingBatch(long startNanos, int size) {
// nothing by default
}
public void addTimingNoBatch(long startNanos) {
// nothing by default
}
/**
* Effectively set start nanos if we are collecting metrics on a label.
*/
@@ -229,6 +229,16 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
initGeneratedProperties();
}
@Override
public void addTimingBatch(long startNanos, int batch) {
beanDescriptor.metricPersistBatch(type, startNanos, batch);
}
@Override
public void addTimingNoBatch(long startNanos) {
beanDescriptor.metricPersistNoBatch(type, startNanos);
}
/**
* Add to profile as batched bean insert, update or delete.
*/
@@ -143,6 +143,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private boolean batchEscalateOnCascadeInsert;
private boolean batchEscalateOnCascadeDelete;
private final BeanIudMetrics iudMetrics;
public enum EntityType {
ORM, EMBEDDED, VIEW, SQL, DOC
}
@@ -441,7 +443,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.beanType = deploy.getBeanType();
this.rootBeanType = PersistenceContextUtil.root(beanType);
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
this.iudMetrics = new BeanIudMetrics(name);
this.namedQuery = deploy.getNamedQuery();
this.namedRawSql = deploy.getNamedRawSql();
this.inheritInfo = deploy.getInheritInfo();
@@ -898,6 +900,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
}
public void metricPersistBatch(PersistRequest.Type type, long startNanos, int size) {
iudMetrics.addBatch(type, startNanos, size);
}
public void metricPersistNoBatch(PersistRequest.Type type, long startNanos) {
iudMetrics.addNoBatch(type, startNanos);
}
public void merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
@@ -1684,6 +1694,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Visit all the ORM query plan metrics (includes UpdateQuery with updates and deletes).
*/
public void visitMetrics(MetricVisitor visitor) {
iudMetrics.visit(visitor);
for (CQueryPlan queryPlan : queryPlanCache.values()) {
if (!queryPlan.isEmptyStats()) {
visitor.visitOrmQuery(queryPlan.getSnapshot(visitor.isReset()));
@@ -0,0 +1,82 @@
package io.ebeaninternal.server.deploy;
import io.ebean.meta.MetricType;
import io.ebean.meta.MetricVisitor;
import io.ebean.metric.MetricFactory;
import io.ebean.metric.TimedMetric;
import io.ebeaninternal.server.core.PersistRequest;
/**
* Metrics for ORM Insert Update and Delete for a given bean type.
*/
class BeanIudMetrics {
private final TimedMetric insert;
private final TimedMetric update;
private final TimedMetric delete;
private final TimedMetric insertBatch;
private final TimedMetric updateBatch;
private final TimedMetric deleteBatch;
/**
* Create for a given bean type.
*/
BeanIudMetrics(String beanShortName) {
MetricFactory metricFactory = MetricFactory.get();
String prefix = "iud." + beanShortName;
this.insert = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".insert");
this.update = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".update");
this.delete = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".delete");
this.insertBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".insertBatch");
this.updateBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".updateBatch");
this.deleteBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".deleteBatch");
}
/**
* Add batch persist metric.
*/
void addBatch(PersistRequest.Type type, long startNanos, int batch) {
switch (type) {
case INSERT:
insertBatch.addBatchSince(startNanos, batch);
break;
case UPDATE:
case DELETE_SOFT:
updateBatch.addBatchSince(startNanos, batch);
break;
case DELETE:
case DELETE_PERMANENT:
deleteBatch.addBatchSince(startNanos, batch);
break;
}
}
/**
* Add Non-batch persist metric.
*/
void addNoBatch(PersistRequest.Type type, long startNanos) {
switch (type) {
case INSERT:
insert.addSinceNanos(startNanos);
break;
case UPDATE:
case DELETE_SOFT:
update.addSinceNanos(startNanos);
break;
case DELETE:
case DELETE_PERMANENT:
delete.addSinceNanos(startNanos);
break;
}
}
void visit(MetricVisitor visitor) {
insert.visit(visitor);
update.visit(visitor);
delete.visit(visitor);
insertBatch.visit(visitor);
updateBatch.visit(visitor);
deleteBatch.visit(visitor);
}
}
@@ -40,4 +40,9 @@ public interface BatchPostExecute {
* Add as event to the profiling.
*/
void profile(long offset, int batchSize);
/**
* Add timing metrics for batch persist.
*/
void addTimingBatch(long startNanos, int batch);
}
@@ -44,6 +44,7 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
private final SpiTransaction transaction;
private long profileStart;
private long timedStart;
private int[] results;
@@ -112,16 +113,23 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
*/
public void executeBatch(boolean getGeneratedKeys) throws SQLException {
this.profileStart = transaction.profileOffset();
timedStart = System.nanoTime();
profileStart = transaction.profileOffset();
executeAndCheckRowCounts();
if (isGenKeys && getGeneratedKeys) {
getGeneratedKeys();
}
postExecute();
close();
addTimingMetrics();
transaction.profileEvent(this);
}
private void addTimingMetrics() {
// just use the first persist request to add batch metrics
list.get(0).addTimingBatch(timedStart, list.size());
}
@Override
public void profile() {
// just use the first to add the event
@@ -151,7 +159,6 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
String s = "results array error " + results.length + " " + list.size();
throw new SQLException(s);
}
// check for concurrency exceptions...
for (int i = 0; i < results.length; i++) {
list.get(i).checkRowCount(results[i]);
@@ -70,7 +70,7 @@ public final class DmlBeanPersister implements BeanPersister {
return -1;
} else {
return handler.execute();
return handler.executeNoBatch();
}
} catch (SQLException e) {
@@ -92,6 +92,16 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
@Override
public abstract int execute() throws SQLException;
@Override
public final int executeNoBatch() throws SQLException {
final long startNanos = System.nanoTime();
try {
return execute();
} finally {
persistRequest.addTimingNoBatch(startNanos);
}
}
/**
* Check the rowCount.
*/
@@ -22,6 +22,11 @@ interface PersistHandler {
*/
int execute() throws SQLException;
/**
* Execute now for non-batch with timing.
*/
int executeNoBatch() throws SQLException;
/**
* Close resources including underlying preparedStatement.
*/
@@ -35,6 +35,17 @@ class DTimedMetric implements TimedMetric {
this.name = name;
}
@Override
public void addBatchSince(long startNanos, int batch) {
if (batch > 0) {
final long totalMicros = (System.nanoTime() - startNanos) / 1000L;
final long mean = totalMicros / batch;
count.add(batch);
total.add(totalMicros);
max.accumulate(mean);
}
}
@Override
public void addSinceNanos(long startNanos) {
add((System.nanoTime() - startNanos) / 1000L);