ENH: Add ProfileLocation - Part 2 - performance metrics for transactions with label and profileLocation

This commit is contained in:
Rob Bygrave
2018-01-22 14:54:27 +13:00
parent 4e33027fdf
commit 51d2e4c600
37 changed files with 779 additions and 33 deletions
+9 -5
View File
@@ -17,17 +17,17 @@ public interface ProfileLocation {
}
/**
* Create and return a new ProfileLocation with a given lineNumber.
* Create and return a new ProfileLocation with a given lineNumber and label.
*/
static ProfileLocation create(int lineNumber) {
return XServiceProvider.profileLocationFactory().create(lineNumber);
static ProfileLocation create(int lineNumber, String label) {
return XServiceProvider.profileLocationFactory().create(lineNumber, label);
}
/**
* Create and return a new ProfileLocation with a given location.
*/
static ProfileLocation create(String location) {
return XServiceProvider.profileLocationFactory().create(location);
static ProfileLocation createAt(String location) {
return XServiceProvider.profileLocationFactory().createAt(location);
}
/**
@@ -40,4 +40,8 @@ public interface ProfileLocation {
*/
String shortDescription();
/**
* Add execution time.
*/
void add(long executionTime);
}
+8
View File
@@ -59,6 +59,14 @@ public interface Transaction extends AutoCloseable {
*/
void register(TransactionCallback callback);
/**
* Set a label on the transaction.
* <p>
* This label is used to group transaction execution times for performance metrics reporting.
* </p>
*/
void setLabel(String label);
/**
* Return true if this transaction is read only.
*/
@@ -7,6 +7,11 @@ import java.util.List;
*/
public interface MetaInfoManager {
/**
* Collect and return the transaction execution metrics.
*/
List<MetaTimedMetric> collectTransactionStatistics(boolean reset);
/**
* Collect and return the non-empty query plan statistics for all the beans.
* <p>
@@ -0,0 +1,43 @@
package io.ebean.meta;
/**
* Timed execution statistics.
*/
public interface MetaTimedMetric {
/**
* Return the metric name.
*/
String getName();
/**
* Return the metric location if defined.
*/
String getLocation();
/**
* Return the time the counters started from.
*/
long getStartTime();
/**
* Return the total count.
*/
long getCount();
/**
* Return the total execution time.
*/
long getTotal();
/**
* Return the max execution time.
*/
long getMax();
/**
* Return the mean execution time.
*/
long getMean();
}
@@ -15,10 +15,10 @@ public interface SpiProfileLocationFactory {
/**
* Create a profile location with a line number.
*/
ProfileLocation create(int lineNumber);
ProfileLocation create(int lineNumber, String label);
/**
* Create a known location.
*/
ProfileLocation create(String location);
ProfileLocation createAt(String location);
}
@@ -25,6 +25,11 @@ import java.sql.SQLException;
*/
public interface SpiTransaction extends Transaction {
/**
* Return the user defined label for the transaction.
*/
String getLabel();
/**
* Return the string prefix with the transaction id and label used in logging.
*/
@@ -30,6 +30,16 @@ abstract class SpiTransactionProxy implements SpiTransaction {
return transaction.translate(message, cause);
}
@Override
public void setLabel(String label) {
transaction.setLabel(label);
}
@Override
public String getLabel() {
return transaction.getLabel();
}
@Override
public void commitAndContinue() {
transaction.commitAndContinue();
@@ -0,0 +1,25 @@
package io.ebeaninternal.metric;
/**
* Factory to create timed metric counters.
*/
public interface MetricFactory {
/**
* Return the factory instance.
*/
static MetricFactory get() {
return MetricServiceProvider.get();
}
/**
* Create a timed metric group.
*/
TimedMetricMap createTimedMetricMap(String name);
/**
* Create a Timed metric.
*/
TimedMetric createTimedMetric(String name);
}
@@ -0,0 +1,31 @@
package io.ebeaninternal.metric;
import io.ebeaninternal.server.profile.DMetricFactory;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* Lookup MetricFactory service.
*/
class MetricServiceProvider {
private static MetricFactory metricFactory = init();
private static MetricFactory init() {
Iterator<MetricFactory> loader = ServiceLoader.load(MetricFactory.class).iterator();
if (loader.hasNext()) {
return loader.next();
}
return new DMetricFactory();
}
/**
* Return the MetricFactory implementation.
*/
static MetricFactory get() {
return metricFactory;
}
}
@@ -0,0 +1,31 @@
package io.ebeaninternal.metric;
import io.ebean.meta.MetaTimedMetric;
import java.util.List;
/**
* Metric for timed events like transaction execution times.
*/
public interface TimedMetric {
/**
* Add a time event (usually in microseconds).
*/
void add(long value);
/**
* Return true if there are no metrics collected since the last collection.
*/
boolean isEmpty();
/**
* Collect the timed metric statistics.
*/
TimedMetricStats collect(boolean reset);
/**
* Add non empty metrics to the result.
*/
void collect(boolean reset, List<MetaTimedMetric> result);
}
@@ -0,0 +1,21 @@
package io.ebeaninternal.metric;
import io.ebean.meta.MetaTimedMetric;
import java.util.List;
/**
* A map of timed metrics keyed by a string.
*/
public interface TimedMetricMap {
/**
* Add an execution for the given key.
*/
void add(String key, long exeMicros);
/**
* Add non empty metrics to the given result.
*/
void collect(boolean reset, List<MetaTimedMetric> result);
}
@@ -0,0 +1,14 @@
package io.ebeaninternal.metric;
import io.ebean.meta.MetaTimedMetric;
/**
* Extend public MetaTimedMetric with ability to set details from profile location.
*/
public interface TimedMetricStats extends MetaTimedMetric {
/**
* Additionally set the location.
*/
void setLocation(String location);
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.core;
import io.ebean.meta.MetaInfoManager;
import io.ebean.meta.MetaObjectGraphNodeStats;
import io.ebean.meta.MetaQueryPlanStatistic;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.query.CQueryPlanStatsCollector;
@@ -20,6 +21,11 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
this.server = server;
}
@Override
public List<MetaTimedMetric> collectTransactionStatistics(boolean reset) {
return server.collectTransactionStatistics(reset);
}
@Override
public List<MetaQueryPlanStatistic> collectQueryPlanStatistics(boolean reset) {
@@ -47,6 +47,7 @@ import io.ebean.event.BeanPersistController;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetaInfoManager;
import io.ebean.meta.MetaTimedMetric;
import io.ebean.plugin.BeanType;
import io.ebean.plugin.Plugin;
import io.ebean.plugin.SpiServer;
@@ -2214,4 +2215,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
}
public List<MetaTimedMetric> collectTransactionStatistics(boolean reset) {
return transactionManager.collectTransactionStatistics(reset);
}
}
@@ -25,6 +25,16 @@ class NoTransaction implements SpiTransaction {
static final NoTransaction INSTANCE = new NoTransaction();
@Override
public void setLabel(String label) {
// do nothing
}
@Override
public String getLabel() {
return null;
}
@Override
public boolean isActive() {
// always false
@@ -416,8 +416,8 @@ public class BeanDescriptor<T> implements BeanType<T> {
this.name = InternString.intern(deploy.getName());
this.baseTableAlias = "t0";
this.fullName = InternString.intern(deploy.getFullName());
this.locationById = ProfileLocation.create(fullName+".byId");
this.locationAll = ProfileLocation.create(fullName+".all");
this.locationById = ProfileLocation.createAt(fullName+".byId");
this.locationAll = ProfileLocation.createAt(fullName+".all");
this.profileBeanId = deploy.getProfileId();
this.beanType = deploy.getBeanType();
this.rootBeanType = PersistenceContextUtil.root(beanType);
@@ -19,6 +19,11 @@ class BasicProfileLocation implements ProfileLocation {
return shortDescription;
}
@Override
public void add(long executionTime) {
// do nothing
}
public String obtain() {
return location;
}
@@ -0,0 +1,21 @@
package io.ebeaninternal.server.profile;
import io.ebeaninternal.metric.MetricFactory;
import io.ebeaninternal.metric.TimedMetric;
import io.ebeaninternal.metric.TimedMetricMap;
/**
* Default metric factory implementation.
*/
public class DMetricFactory implements MetricFactory {
@Override
public TimedMetricMap createTimedMetricMap(String name) {
return new DTimedMetricMap(name);
}
@Override
public TimedMetric createTimedMetric(String name) {
return new DTimedMetric(name);
}
}
@@ -18,9 +18,12 @@ class DProfileLocation implements ProfileLocation {
private final int lineNumber;
DProfileLocation() {
this.lineNumber = 0;
this(0);
}
/**
* Create with a given line number.
*/
DProfileLocation(int lineNumber) {
this.lineNumber = lineNumber;
}
@@ -29,6 +32,11 @@ class DProfileLocation implements ProfileLocation {
return "location: " + location;
}
@Override
public void add(long executionTime) {
// do nothing
}
public String obtain() {
// atomic assignment so happy with this
if (location == null) {
@@ -2,6 +2,8 @@ package io.ebeaninternal.server.profile;
import io.ebean.ProfileLocation;
import io.ebean.service.SpiProfileLocationFactory;
import io.ebeaninternal.metric.MetricFactory;
import io.ebeaninternal.metric.TimedMetric;
/**
* Default implementation of the profile location factory.
@@ -14,12 +16,17 @@ public class DProfileLocationFactory implements SpiProfileLocationFactory {
}
@Override
public ProfileLocation create(int lineNumber) {
return new DProfileLocation(lineNumber);
public ProfileLocation create(int lineNumber, String label) {
TimedMetric timedMetric = MetricFactory.get().createTimedMetric("txn.named." + label);
DTimedProfileLocation loc = new DTimedProfileLocation(lineNumber, label, timedMetric);
TimedProfileLocationRegistry.register(loc);
return loc;
}
@Override
public ProfileLocation create(String location) {
public ProfileLocation createAt(String location) {
return new BasicProfileLocation(location);
}
}
@@ -0,0 +1,100 @@
package io.ebeaninternal.server.profile;
import io.ebeaninternal.metric.TimedMetricStats;
/**
* Snapshot of the current statistics for a Counter or TimeCounter.
*/
class DTimeMetricStats implements TimedMetricStats {
private final String name;
private String location;
private final long startTime;
private final long count;
private final long total;
private final long max;
DTimeMetricStats(String name, long collectionStart, long count, long total, long max) {
this.name = name;
this.startTime = collectionStart;
this.count = count;
this.total = total;
// collection is racy so sanitize the max value if it has not been set
// this most likely would happen when count = 1 so max = mean
this.max = max != Long.MIN_VALUE ? max : (count < 1 ? 0 : Math.round(total / count));
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (location != null) {
sb.append("loc:").append(location).append(" ");
}
if (name != null) {
sb.append("name:").append(name).append(" ");
}
sb.append("count:").append(count)
.append(" total:").append(total)
.append(" max:").append(max);
return sb.toString();
}
public void setLocation(String location) {
this.location = location;
}
@Override
public String getName() {
return name;
}
@Override
public String getLocation() {
return location;
}
/**
* Return the time the counter started statistics collection.
*/
@Override
public long getStartTime() {
return startTime;
}
/**
* Return the count of values collected.
*/
@Override
public long getCount() {
return count;
}
/**
* Return the total of all the values.
*/
@Override
public long getTotal() {
return total;
}
/**
* Return the Max value collected.
*/
@Override
public long getMax() {
return max;
}
/**
* Return the mean value rounded up.
*/
@Override
public long getMean() {
return (count < 1) ? 0L : Math.round((double)(total / count));
}
}
@@ -0,0 +1,127 @@
package io.ebeaninternal.server.profile;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.metric.TimedMetric;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
/**
* Used to collect timed execution statistics.
* <p>
* It is intended for high concurrent updates to the statistics and relatively infrequent reads.
* </p>
*/
class DTimedMetric implements TimedMetric {
protected final String name;
protected final LongAdder count = new LongAdder();
protected final LongAdder total = new LongAdder();
protected final LongAccumulator max = new LongAccumulator(Math::max, Long.MIN_VALUE);
protected final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
DTimedMetric(String name) {
this.name = name;
}
/**
* Add a value. Usually the value is Time or Bytes etc.
*/
@Override
public void add(long value) {
count.increment();
total.add(value);
max.accumulate(value);
}
@Override
public boolean isEmpty() {
return count.sum() == 0;
}
@Override
public void collect(boolean reset, List<MetaTimedMetric> result) {
DTimeMetricStats metric = collect(reset);
if (metric != null) {
result.add(metric);
}
}
// @Override
public DTimeMetricStats collect(boolean reset) {
boolean empty = count.sum() == 0;
if (empty) {
if (reset) {
startTime.set(System.currentTimeMillis());
}
return null;
} else {
return getStatistics(reset);
}
}
/**
* Return the current statistics resetting the internal values if reset is true.
*/
public DTimeMetricStats getStatistics(boolean reset) {
if (reset) {
// Note these values are not guaranteed to be consistent wrt each other
// but should be reasonably consistent (small time between count and total)
final long maxVal = max.getThenReset();
final long totalVal = total.sumThenReset();
final long countVal = count.sumThenReset();
final long startTimeVal = startTime.getAndSet(System.currentTimeMillis());
return new DTimeMetricStats(name, startTimeVal, countVal, totalVal, maxVal);
} else {
return new DTimeMetricStats(name, startTime.get(), count.sum(), total.sum(), max.get());
}
}
/**
* Reset all the internal counters and start time.
*/
public void reset() {
startTime.set(System.currentTimeMillis());
max.reset();
count.reset();
total.reset();
}
/**
* Return the start time.
*/
public long getStartTime() {
return startTime.get();
}
/**
* Return the count of values.
*/
public long getCount() {
return count.sum();
}
/**
* Return the total of values.
*/
public long getTotal() {
return total.sum();
}
/**
* Return the max value.
*/
public long getMax() {
return max.get();
}
}
@@ -0,0 +1,30 @@
package io.ebeaninternal.server.profile;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.metric.TimedMetricMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
class DTimedMetricMap implements TimedMetricMap {
private final String name;
private final ConcurrentHashMap<String, DTimedMetric> map = new ConcurrentHashMap<>();
DTimedMetricMap(String name) {
this.name = name;
}
@Override
public void add(String key, long exeMicros) {
map.computeIfAbsent(key, (k)-> new DTimedMetric(name + key)).add(exeMicros);
}
@Override
public void collect(boolean reset, List<MetaTimedMetric> list) {
for (DTimedMetric value : map.values()) {
value.collect(reset, list);
}
}
}
@@ -0,0 +1,49 @@
package io.ebeaninternal.server.profile;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.metric.TimedMetric;
import io.ebeaninternal.metric.TimedMetricStats;
import java.util.List;
/**
* Default profile location that uses stack trace.
*/
class DTimedProfileLocation extends DProfileLocation implements TimedProfileLocation {
private final String label;
private final TimedMetric timedMetric;
DTimedProfileLocation(int lineNumber, String label, TimedMetric timedMetric) {
super(lineNumber);
this.label = label;
this.timedMetric = timedMetric;
}
@Override
public String getLabel() {
return label;
}
@Override
public TimedMetric getMetric() {
return timedMetric;
}
@Override
public void add(long executionTime) {
timedMetric.add(executionTime);
}
@Override
public void collect(boolean reset, List<MetaTimedMetric> list) {
TimedMetricStats collect = timedMetric.collect(reset);
if (collect != null) {
collect.setLocation(obtain());
list.add(collect);
}
}
}
@@ -0,0 +1,28 @@
package io.ebeaninternal.server.profile;
import io.ebean.ProfileLocation;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.metric.TimedMetric;
import java.util.List;
/**
* ProfileLocation that collects timing metrics.
*/
public interface TimedProfileLocation extends ProfileLocation {
/**
* Return the label.
*/
String getLabel();
/**
* Return the metric.
*/
TimedMetric getMetric();
/**
* Collect the metrics adding to the given list if the metrics are non empty.
*/
void collect(boolean reset, List<MetaTimedMetric> list);
}
@@ -0,0 +1,27 @@
package io.ebeaninternal.server.profile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Global registry of the TimedProfileLocation instances created.
*/
public class TimedProfileLocationRegistry {
private static final List<TimedProfileLocation> list = Collections.synchronizedList(new ArrayList<TimedProfileLocation>());
/**
* Register the timed profile location instance.
*/
public static void register(TimedProfileLocation location) {
list.add(location);
}
/**
* Return all the registered timed locations.
*/
public static List<TimedProfileLocation> registered() {
return list;
}
}
@@ -41,6 +41,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
private static final String notExpectedMessage = "Not expected on read only transaction";
private final TransactionManager manager;
/**
* The status of the transaction.
*/
@@ -61,23 +63,37 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
private Map<String, Object> userObjects;
private long startNanos;
/**
* Create without a tenantId.
*/
ImplicitReadOnlyTransaction(Connection connection) {
ImplicitReadOnlyTransaction(TransactionManager manager, Connection connection) {
this.manager = manager;
this.active = true;
this.connection = connection;
this.persistenceContext = new DefaultPersistenceContext();
this.startNanos = System.nanoTime();
}
/**
* Create with a tenantId.
*/
ImplicitReadOnlyTransaction(Connection connection, Object tenantId) {
this(connection);
ImplicitReadOnlyTransaction(TransactionManager manager, Connection connection, Object tenantId) {
this(manager, connection);
this.tenantId = tenantId;
}
@Override
public void setLabel(String label) {
// do nothing
}
@Override
public String getLabel() {
return null;
}
@Override
public long profileOffset() {
return 0;
@@ -475,6 +491,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
}
connection = null;
active = false;
long exeMicros = (System.nanoTime() - startNanos) / 1000L;
manager.collectMetricReadOnly(exeMicros);
}
/**
@@ -55,6 +55,11 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
*/
protected final String id;
/**
* The user defined label to group execution statistics.
*/
protected String label;
/**
* Flag to indicate if this was an explicitly created Transaction.
*/
@@ -176,6 +181,8 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
protected ProfileLocation profileLocation;
protected final long startNanos;
/**
* Create without ProfileStream option (no profiling).
*/
@@ -196,6 +203,7 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
this.manager = manager;
this.connection = connection;
this.persistenceContext = new DefaultPersistenceContext();
this.startNanos = System.nanoTime();
if (manager == null) {
this.skipCacheAfterWrite = true;
@@ -216,6 +224,16 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
}
}
@Override
public void setLabel(String label) {
this.label = label;
}
@Override
public String getLabel() {
return label;
}
@Override
public long profileOffset() {
return (profileStream == null) ? 0 : profileStream.offset();
@@ -980,8 +998,17 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
}
private void profileEnd() {
if (profileStream != null) {
profileStream.end(manager);
if (manager != null) {
long exeMicros = (System.nanoTime() - startNanos) / 1000L;
if (profileLocation != null) {
profileLocation.add(exeMicros);
} else if (label != null) {
manager.collectMetricNamed(exeMicros, label);
}
manager.collectMetric(exeMicros);
if (profileStream != null) {
profileStream.end(manager);
}
}
}
@@ -32,7 +32,7 @@ class TransactionFactoryBasicWithRead extends TransactionFactoryBasic {
Connection connection = null;
try {
connection = readOnlyDataSource.getConnection();
return new ImplicitReadOnlyTransaction(connection);
return new ImplicitReadOnlyTransaction(manager, connection);
} catch (PersistenceException ex) {
JdbcClose.close(connection);
@@ -32,7 +32,7 @@ class TransactionFactoryTenantWithRead extends TransactionFactoryTenant {
tenantId = tenantProvider.currentId();
}
connection = dataSourceSupplier.getReadOnlyConnection(tenantId);
return new ImplicitReadOnlyTransaction(connection, tenantId);
return new ImplicitReadOnlyTransaction(manager, connection, tenantId);
} catch (PersistenceException ex) {
JdbcClose.close(connection);
@@ -8,13 +8,19 @@ import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeSet;
import io.ebean.meta.MetaTimedMetric;
import io.ebeaninternal.api.SpiProfileHandler;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.TransactionEvent;
import io.ebeaninternal.api.TransactionEventTable;
import io.ebeaninternal.api.TransactionEventTable.TableIUD;
import io.ebeaninternal.metric.MetricFactory;
import io.ebeaninternal.metric.TimedMetric;
import io.ebeaninternal.metric.TimedMetricMap;
import io.ebeaninternal.server.cluster.ClusterManager;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.profile.TimedProfileLocation;
import io.ebeaninternal.server.profile.TimedProfileLocationRegistry;
import io.ebeanservice.docstore.api.DocStoreTransaction;
import io.ebeanservice.docstore.api.DocStoreUpdateProcessor;
import io.ebeanservice.docstore.api.DocStoreUpdates;
@@ -25,6 +31,7 @@ import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -113,6 +120,11 @@ public class TransactionManager {
private final SpiProfileHandler profileHandler;
private final MetricFactory metricFactory;
private final TimedMetric txnMain;
private final TimedMetric txnReadOnly;
private final TimedMetricMap txnNamed;
/**
* Create the TransactionManager
*/
@@ -142,6 +154,10 @@ public class TransactionManager {
CurrentTenantProvider tenantProvider = options.config.getCurrentTenantProvider();
this.transactionFactory = TransactionFactoryBuilder.build(this, dataSourceSupplier, tenantProvider);
this.metricFactory = MetricFactory.get();
this.txnMain = metricFactory.createTimedMetric("txn.main");
this.txnReadOnly = metricFactory.createTimedMetric("txn.readonly");
this.txnNamed = metricFactory.createTimedMetricMap("txn.named.");
}
/**
@@ -266,7 +282,7 @@ public class TransactionManager {
protected SpiTransaction createTransaction(int profileId, boolean explicit, Connection c, long id) {
ProfileStream profileStream = profileHandler.createProfileStream(profileId);
return new JdbcTransaction(profileStream,prefix + id, explicit, c, this);
return new JdbcTransaction(profileStream, prefix + id, explicit, c, this);
}
/**
@@ -424,4 +440,42 @@ public class TransactionManager {
public void profileCollect(TransactionProfile transactionProfile) {
profileHandler.collectTransactionProfile(transactionProfile);
}
/**
* Collect execution time for an explicit transaction.
*/
public void collectMetric(long exeMicros) {
txnMain.add(exeMicros);
}
/**
* Collect execution time for implicit read only transaction.
*/
public void collectMetricReadOnly(long exeMicros) {
txnReadOnly.add(exeMicros);
}
/**
* Collect execution time for a named transaction.
*/
public void collectMetricNamed(long exeMicros, String label) {
txnNamed.add(label, exeMicros);
}
/**
* Collect the transaction execution statistics since the last reset.
*/
public List<MetaTimedMetric> collectTransactionStatistics(boolean reset) {
List<MetaTimedMetric> list = new ArrayList<>();
txnMain.collect(reset, list);
txnReadOnly.collect(reset, list);
for (TimedProfileLocation timedLocation : TimedProfileLocationRegistry.registered()) {
timedLocation.collect(reset, list);
}
txnNamed.collect(reset, list);
return list;
}
}