diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java b/ebean-core/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java index 619f9f9218..2c283a9690 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java @@ -3,8 +3,6 @@ import io.ebean.meta.MetricVisitor; import io.ebean.metric.TimedMetric; -import java.util.concurrent.atomic.LongAccumulator; - /** * Used to collect timed execution statistics. *
@@ -16,12 +14,17 @@ final class DTimedMetric implements TimedMetric {
private final String name;
private final ValueAdder count = new ValueAdder();
private final ValueAdder total = new ValueAdder();
- private final LongAccumulator max = new LongAccumulator(Math::max, 0);
+ private final ValueMax max;
private boolean collected;
private String reportName;
DTimedMetric(String name) {
+ this(name, new ValueMax());
+ }
+
+ DTimedMetric(String name, ValueMax max) {
this.name = name;
+ this.max = max;
}
@Override
@@ -31,7 +34,7 @@ public void addBatchSince(long startNanos, int batch) {
final long mean = totalMicros / batch;
count.add(batch);
total.add(totalMicros);
- max.accumulate(mean);
+ max.add(mean);
}
}
@@ -44,7 +47,7 @@ public void addSinceNanos(long startNanos) {
public void add(long value) {
count.add(1);
total.add(value);
- max.accumulate(value);
+ max.add(value);
}
@Override
@@ -76,6 +79,7 @@ public DTimeMetricStats collect(boolean reset) {
@Override
public DTimeMetricStats collect(MetricVisitor.Mode mode) {
+ final long maxValue = max.collect();
final long countSum;
switch (mode) {
case RESET:
@@ -93,14 +97,14 @@ public DTimeMetricStats collect(MetricVisitor.Mode mode) {
if (countSum == 0) {
return null;
} else {
- return stats(mode, name, countSum);
+ return stats(mode, name, countSum, maxValue);
}
}
/**
* Return the current statistics resetting the internal values if reset is true.
*/
- private DTimeMetricStats stats(MetricVisitor.Mode mode, String name, long countSum) {
+ private DTimeMetricStats stats(MetricVisitor.Mode mode, String name, long countSum, long maxValue) {
try {
final long totalSum;
switch (mode) {
@@ -116,7 +120,7 @@ private DTimeMetricStats stats(MetricVisitor.Mode mode, String name, long countS
default:
throw new IllegalStateException("Unknown metric collection mode");
}
- return new DTimeMetricStats(name, collected, countSum, totalSum, max.getThenReset());
+ return new DTimeMetricStats(name, collected, countSum, totalSum, maxValue);
} finally {
collected = true;
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/profile/ValueMax.java b/ebean-core/src/main/java/io/ebeaninternal/server/profile/ValueMax.java
new file mode 100644
index 0000000000..11e3a77028
--- /dev/null
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/profile/ValueMax.java
@@ -0,0 +1,48 @@
+package io.ebeaninternal.server.profile;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAccumulator;
+import java.util.function.LongSupplier;
+
+/**
+ * Accumulates a maximum value and publishes it in rolling 59-second windows.
+ */
+final class ValueMax {
+
+ private static final long WINDOW_NANOS = TimeUnit.SECONDS.toNanos(59);
+
+ private final LongSupplier nanoTime;
+ private final LongAccumulator value;
+ private volatile long published;
+ private long lastResetNanos;
+
+ ValueMax() {
+ this(System::nanoTime);
+ }
+
+ ValueMax(LongSupplier nanoTime) {
+ this.nanoTime = nanoTime;
+ this.value = new LongAccumulator(Math::max, 0);
+ this.lastResetNanos = nanoTime.getAsLong() - 2 * WINDOW_NANOS;
+ }
+
+ void add(long amount) {
+ value.accumulate(amount);
+ }
+
+ synchronized long collect() {
+ long now = nanoTime.getAsLong();
+ if (now - lastResetNanos >= WINDOW_NANOS) {
+ published = value.getThenReset();
+ lastResetNanos = now;
+ }
+ return published;
+ }
+
+ synchronized void reset() {
+ value.reset();
+ published = 0;
+ lastResetNanos = nanoTime.getAsLong() - 2 * WINDOW_NANOS;
+ }
+
+}
diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/profile/DQueryPlanMetricTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/profile/DQueryPlanMetricTest.java
index 5f8651fdbc..55298cf00b 100644
--- a/ebean-core/src/test/java/io/ebeaninternal/server/profile/DQueryPlanMetricTest.java
+++ b/ebean-core/src/test/java/io/ebeaninternal/server/profile/DQueryPlanMetricTest.java
@@ -5,19 +5,22 @@
import org.junit.jupiter.api.Test;
import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import static org.assertj.core.api.Assertions.assertThat;
class DQueryPlanMetricTest {
+ private final AtomicLong nanoTime = new AtomicLong();
Function