diff --git a/src/main/java/com/zaxxer/hikari/metrics/PoolStats.java b/src/main/java/com/zaxxer/hikari/metrics/PoolStats.java index e8905d10..e4d95f11 100644 --- a/src/main/java/com/zaxxer/hikari/metrics/PoolStats.java +++ b/src/main/java/com/zaxxer/hikari/metrics/PoolStats.java @@ -16,31 +16,40 @@ package com.zaxxer.hikari.metrics; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLong; + import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.plusMillis; -import java.util.concurrent.atomic.AtomicLong; - /** * * @author Brett Wooldridge */ +@SuppressWarnings("unused") public abstract class PoolStats { + private static final AtomicIntegerFieldUpdater fieldUpdater; + private final AtomicLong reloadAt; private final long timeoutMs; + private volatile int peakActiveConnections; protected volatile int totalConnections; protected volatile int idleConnections; protected volatile int activeConnections; protected volatile int pendingThreads; + static { + fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(PoolStats.class, "peakActiveConnections"); + } + public PoolStats(final long timeoutMs) { this.timeoutMs = timeoutMs; this.reloadAt = new AtomicLong(); } - + public int getTotalConnections() { if (shouldLoad()) { @@ -77,6 +86,16 @@ public abstract class PoolStats return pendingThreads; } + public int getPeakActiveConnections() + { + return fieldUpdater.getAndSet(this, 0); + } + + public void setPeakActiveConnections(final int peak) + { + fieldUpdater.lazySet(this, peak); + } + protected abstract void update(); private boolean shouldLoad() diff --git a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index 48506dc2..d6efb450 100644 --- a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -291,7 +291,8 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory) { if (metricsTrackerFactory != null) { - this.metricsTracker = new MetricsTrackerDelegate(metricsTrackerFactory.create(config.getPoolName(), getPoolStats())); + final PoolStats poolStats = getPoolStats(); + this.metricsTracker = new MetricsTrackerDelegate(metricsTrackerFactory.create(config.getPoolName(), poolStats), poolStats); } else { this.metricsTracker = new NopMetricsTrackerDelegate(); diff --git a/src/main/java/com/zaxxer/hikari/pool/PoolBase.java b/src/main/java/com/zaxxer/hikari/pool/PoolBase.java index 655322e7..0c02e93e 100644 --- a/src/main/java/com/zaxxer/hikari/pool/PoolBase.java +++ b/src/main/java/com/zaxxer/hikari/pool/PoolBase.java @@ -30,6 +30,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReference; import javax.management.MBeanServer; @@ -38,6 +39,7 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; +import com.zaxxer.hikari.metrics.PoolStats; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -693,16 +695,29 @@ abstract class PoolBase */ static class MetricsTrackerDelegate implements IMetricsTrackerDelegate { + private static final AtomicIntegerFieldUpdater activeUpdater; + private static final AtomicIntegerFieldUpdater maxActiveUpdater; + final IMetricsTracker tracker; + final PoolStats poolStats; + volatile int activeCount; + volatile int maxActiveCount; + + static { + activeUpdater = AtomicIntegerFieldUpdater.newUpdater(MetricsTrackerDelegate.class, "activeCount"); + maxActiveUpdater = AtomicIntegerFieldUpdater.newUpdater(MetricsTrackerDelegate.class, "maxActiveCount"); + } - MetricsTrackerDelegate(IMetricsTracker tracker) + MetricsTrackerDelegate(IMetricsTracker tracker, PoolStats poolStats) { this.tracker = tracker; + this.poolStats = poolStats; } @Override public void recordConnectionUsage(final PoolEntry poolEntry) { + activeUpdater.decrementAndGet(this); tracker.recordConnectionUsageMillis(poolEntry.getMillisSinceBorrowed()); } @@ -723,6 +738,15 @@ abstract class PoolBase { final long now = currentTime(); poolEntry.lastBorrowed = now; + + final int active = activeUpdater.incrementAndGet(this); + final int maxActive = maxActiveUpdater.get(this); + if (active > maxActive) { + if (maxActive < maxActiveUpdater.getAndUpdate(this, (current) -> (active > current) ? active : current)) { + poolStats.setPeakActiveConnections(active); + } + } + tracker.recordConnectionAcquiredNanos(elapsedNanos(startTime, now)); }