All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.jdbc.pool.monitor.JdbcConnPoolStatsProvider Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jdbc.pool.monitor;

import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.resource.pool.PoolLifeCycleListenerRegistry;
import com.sun.enterprise.resource.pool.PoolStatus;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.api.naming.SimpleJndiName;
import org.glassfish.external.probe.provider.annotations.ProbeListener;
import org.glassfish.external.probe.provider.annotations.ProbeParam;
import org.glassfish.external.statistics.CountStatistic;
import org.glassfish.external.statistics.RangeStatistic;
import org.glassfish.external.statistics.annotations.Reset;
import org.glassfish.external.statistics.impl.CountStatisticImpl;
import org.glassfish.external.statistics.impl.RangeStatisticImpl;
import org.glassfish.external.statistics.impl.StatisticImpl;
import org.glassfish.gmbal.AMXMetadata;
import org.glassfish.gmbal.Description;
import org.glassfish.gmbal.ManagedAttribute;
import org.glassfish.gmbal.ManagedObject;
import org.glassfish.resourcebase.resources.api.PoolInfo;

/**
 * StatsProvider object for Jdbc pool monitoring.
 *
 * Implements various events related to jdbc pool monitoring and provides
 * objects to the calling modules that retrieve monitoring information.
 *
 * @author Shalini M
 */
@AMXMetadata(type="jdbc-connection-pool-mon", group="monitoring")
@ManagedObject
@Description("JDBC Statistics")
public class JdbcConnPoolStatsProvider {

    private final PoolInfo poolInfo;
    private final Logger logger;

    //Registry that stores all listeners to this object
    private PoolLifeCycleListenerRegistry poolRegistry;


    //Objects that are exposed by this telemetry
    private final CountStatisticImpl numConnFailedValidation = new CountStatisticImpl(
            "NumConnFailedValidation", StatisticImpl.UNIT_COUNT,
            "The total number of connections in the connection pool that failed " +
            "validation from the start time until the last sample time.");

    private final CountStatisticImpl numConnTimedOut = new CountStatisticImpl(
            "NumConnTimedOut", StatisticImpl.UNIT_COUNT, "The total number of " +
            "connections in the pool that timed out between the start time and the last sample time.");

    private final RangeStatisticImpl numConnFree = new RangeStatisticImpl(
            0, 0, 0,
            "NumConnFree", StatisticImpl.UNIT_COUNT, "The total number of free " +
            "connections in the pool as of the last sampling.",
            System.currentTimeMillis(), System.currentTimeMillis());

    private final RangeStatisticImpl numConnUsed = new RangeStatisticImpl(
            0, 0, 0,
            "NumConnUsed", StatisticImpl.UNIT_COUNT, "Provides connection usage " +
            "statistics. The total number of connections that are currently being " +
            "used, as well as information about the maximum number of connections " +
            "that were used (the high water mark).",
            System.currentTimeMillis(), System.currentTimeMillis());

    private final RangeStatisticImpl connRequestWaitTime = new RangeStatisticImpl(
            0, 0, 0,
            "ConnRequestWaitTime", StatisticImpl.UNIT_MILLISECOND,
            "The longest and shortest wait times of connection requests. The " +
            "current value indicates the wait time of the last request that was " +
            "serviced by the pool.",
            System.currentTimeMillis(), System.currentTimeMillis());

    private final CountStatisticImpl numConnDestroyed = new CountStatisticImpl(
            "NumConnDestroyed", StatisticImpl.UNIT_COUNT,
            "Number of physical connections that were destroyed since the last reset.");

    private final CountStatisticImpl numConnAcquired = new CountStatisticImpl(
            "NumConnAcquired", StatisticImpl.UNIT_COUNT, "Number of logical " +
            "connections acquired from the pool.");

    private final CountStatisticImpl numConnReleased = new CountStatisticImpl(
            "NumConnReleased", StatisticImpl.UNIT_COUNT, "Number of logical " +
            "connections released to the pool.");
    private final CountStatisticImpl numConnCreated = new CountStatisticImpl(
            "NumConnCreated", StatisticImpl.UNIT_COUNT,
            "The number of physical connections that were created since the last reset.");
    private final CountStatisticImpl numPotentialConnLeak = new CountStatisticImpl(
            "NumPotentialConnLeak", StatisticImpl.UNIT_COUNT,
            "Number of potential connection leaks");
    private final CountStatisticImpl numConnSuccessfullyMatched = new CountStatisticImpl(
            "NumConnSuccessfullyMatched", StatisticImpl.UNIT_COUNT,
            "Number of connections succesfully matched");
    private final CountStatisticImpl numConnNotSuccessfullyMatched = new CountStatisticImpl(
            "NumConnNotSuccessfullyMatched", StatisticImpl.UNIT_COUNT,
            "Number of connections rejected during matching");
    private final CountStatisticImpl totalConnRequestWaitTime = new CountStatisticImpl(
            "TotalConnRequestWaitTime", StatisticImpl.UNIT_MILLISECOND,
            "Total wait time per successful connection request");
    private final CountStatisticImpl averageConnWaitTime = new CountStatisticImpl(
            "AverageConnWaitTime", StatisticImpl.UNIT_MILLISECOND,
            "Average wait-time-duration per successful connection request");
    private final CountStatisticImpl waitQueueLength = new CountStatisticImpl(
            "WaitQueueLength", StatisticImpl.UNIT_COUNT,
            "Number of connection requests in the queue waiting to be serviced.");
    private static final String JDBC_PROBE_LISTENER = "glassfish:jdbc:connection-pool:";


    public JdbcConnPoolStatsProvider(PoolInfo poolInfo, Logger logger) {
        this.poolInfo = poolInfo;
        this.logger = logger;
    }

    /**
     * Whenever connection leak happens, increment numPotentialConnLeak
     * @param pool JdbcConnectionPool that got a connLeakEvent
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "potentialConnLeakEvent")
    public void potentialConnLeakEvent(@ProbeParam("poolName") String poolName,
                                       @ProbeParam("appName") String appName,
                                       @ProbeParam("moduleName") String moduleName
                                       ) {
        // handle the conn leak probe event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection Leak event received - poolName = " +
                             poolName);
            }
            //TODO V3: Checking if this is a valid event
            //Increment counter
            numPotentialConnLeak.increment();
        }
    }

    /**
     * Whenever connection timed-out event occurs, increment numConnTimedOut
     * @param pool JdbcConnectionPool that got a connTimedOutEvent
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionTimedOutEvent")
    public void connectionTimedOutEvent(@ProbeParam("poolName") String poolName,
                                        @ProbeParam("appName") String appName,
                                        @ProbeParam("moduleName") String moduleName
                                        ) {
        // handle the conn timed out probe event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection Timed-out event received - poolName = " +
                             poolName);
            }
            //Increment counter
            numConnTimedOut.increment();
        }
    }

    /**
     * Decrement numconnfree event
     * @param poolName
     * @param steadyPoolSize
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "decrementNumConnFreeEvent")
    public void decrementNumConnFreeEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {
        // handle the num conn free decrement event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Decrement Num Connections Free event received - poolName = " +
                             poolName);
            }
            //Decrement counter
            synchronized(numConnFree) {
                numConnFree.setCurrent(numConnFree.getCurrent() - 1);
            }
        }
    }

    /**
     * Increment numconnfree event
     * @param poolName
     * @param steadyPoolSize
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "incrementNumConnFreeEvent")
    public void incrementNumConnFreeEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName,
            @ProbeParam("beingDestroyed") boolean beingDestroyed,
            @ProbeParam("steadyPoolSize") int steadyPoolSize) {
        // handle the num conn free increment event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if (this.poolInfo.equals(poolInfo)) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Increment Num Connections Free event received - poolName = " + poolName);
            }
            if (beingDestroyed) {
                // if pruned by resizer thread
                synchronized (numConnFree) {
                    synchronized (numConnUsed) {
                        if (numConnFree.getCurrent() + numConnUsed.getCurrent() < steadyPoolSize) {
                            numConnFree.setCurrent(numConnFree.getCurrent() + 1);
                        }
                    }
                }
            } else {
                synchronized (numConnFree) {
                    numConnFree.setCurrent(numConnFree.getCurrent() + 1);
                }
            }
        }
    }

    /**
     * Decrement numConnUsed event
     * @param poolName
     * @param beingDestroyed if the connection is destroyed due to error
     * @param steadyPoolSize
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "decrementConnectionUsedEvent")
    public void decrementConnectionUsedEvent(@ProbeParam("poolName") String poolName, @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName) {

        // handle the num conn used decrement event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if (this.poolInfo.equals(poolInfo)) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Decrement Num Connections Used event received - poolName = " + poolName);
            }
            // Decrement numConnUsed counter
            synchronized (numConnUsed) {
                numConnUsed.setCurrent(numConnUsed.getCurrent() - 1);
            }
        }
    }

    /**
     * Connections freed event
     * @param poolName
     * @param count number of connections freed to the pool
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionsFreedEvent")
    public void connectionsFreedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName,
            @ProbeParam("count") int count) {
        // handle the connections freed event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if (this.poolInfo.equals(poolInfo)) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Connections Freed event received - poolName = " + poolName);
                logger.finest("numConnUsed =" + numConnUsed.getCurrent() + " numConnFree=" + numConnFree.getCurrent()
                        + " Number of connections freed =" + count);
            }
            // set numConnFree to the count value
            synchronized (numConnFree) {
                numConnFree.setCurrent(count);
            }
        }
    }

    /**
     * Connection used event
     * @param poolName
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionUsedEvent")
    public void connectionUsedEvent(@ProbeParam("poolName") String poolName, @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName) {

        // handle the connection used event
        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if (this.poolInfo.equals(poolInfo)) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection Used event received - poolName = " + poolName);
            }
            // increment numConnUsed
            synchronized (numConnUsed) {
                numConnUsed.setCurrent(numConnUsed.getCurrent() + 1);
            }
        }
    }

    /**
     * Whenever connection leak happens, increment numConnFailedValidation
     * @param pool JdbcConnectionPool that got a failed validation event
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionValidationFailedEvent")
    public void connectionValidationFailedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName,
            @ProbeParam("increment") int increment) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if (this.poolInfo.equals(poolInfo)) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection Validation Failed event received - " + "poolName = " + poolName);
            }

            // TODO V3 : add support in CounterImpl for addAndGet(increment)
            numConnFailedValidation.increment(increment);
        }

    }

    /**
     * Event that a connection request is served in timeTakenInMillis.
     *
     * @param poolName
     * @param timeTakenInMillis
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionRequestServedEvent")
    public void connectionRequestServedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName,
            @ProbeParam("timeTakenInMillis") long timeTakenInMillis) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection request served event received - " +
                    "poolName = " + poolName);
            }
            connRequestWaitTime.setCurrent(timeTakenInMillis);
            totalConnRequestWaitTime.increment(timeTakenInMillis);
        }
    }

    /**
     * When connection destroyed event is got increment numConnDestroyed.
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionDestroyedEvent")
    public void connectionDestroyedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection destroyed event received - " +
                    "poolName = " + poolName);
            }
            numConnDestroyed.increment();
        }
    }

    /**
     * When a connection is acquired increment counter
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionAcquiredEvent")
    public void connectionAcquiredEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection acquired event received - " +
                    "poolName = " + poolName);
            }
            numConnAcquired.increment();
        }
    }

    /**
     * When a connection is released increment counter
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionReleasedEvent")
    public void connectionReleasedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection released event received - " +
                    "poolName = " + poolName);
            }
            numConnReleased.increment();
        }
    }

    /**
     * When a connection is created increment counter
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionCreatedEvent")
    public void connectionCreatedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection created event received - " +
                    "poolName = " + poolName);
            }
            numConnCreated.increment();
        }
    }

    /**
     * Reset pool statistics.
     * When annotated with @Reset, this method is invoked whenever monitoring
     * is turned to HIGH from OFF, thereby setting the statistics to
     * appropriate values.
     */
    @Reset
    public void reset() {
        if(logger.isLoggable(Level.FINEST)) {
            logger.finest("Reset event received - poolInfo = " + poolInfo);
        }
        PoolStatus status = ConnectorRuntime.getRuntime().getPoolManager().getPoolStatus(poolInfo);
        numConnUsed.setCurrent(status.getNumConnUsed());
        numConnFree.setCurrent(status.getNumConnFree());
        numConnCreated.reset();
        numConnDestroyed.reset();
        numConnFailedValidation.reset();
        numConnTimedOut.reset();
        numConnAcquired.reset();
        numConnReleased.reset();
        connRequestWaitTime.reset();
        numConnSuccessfullyMatched.reset();
        numConnNotSuccessfullyMatched.reset();
        numPotentialConnLeak.reset();
        averageConnWaitTime.reset();
        totalConnRequestWaitTime.reset();
        waitQueueLength.reset();
    }

    /**
     * When connection under test matches the current request ,
     * increment numConnSuccessfullyMatched.
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionMatchedEvent")
    public void connectionMatchedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection matched event received - " +
                    "poolName = " + poolName);
            }
            numConnSuccessfullyMatched.increment();
        }
    }

    /**
     * When a connection under test does not match the current request,
     * increment numConnNotSuccessfullyMatched.
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionNotMatchedEvent")
    public void connectionNotMatchedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Connection not matched event received - " +
                    "poolName = " + poolName);
            }
            numConnNotSuccessfullyMatched.increment();
        }
    }

    /**
     * When an object is added to wait queue, increment the waitQueueLength.
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionRequestQueuedEvent")
    public void connectionRequestQueuedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Wait Queue length modified event received - " +
                    "poolName = " + poolName);
            }
            waitQueueLength.increment();
        }
    }

    /**
     * When an object is removed from the wait queue, decrement the waitQueueLength.
     */
    @ProbeListener(JDBC_PROBE_LISTENER + "connectionRequestDequeuedEvent")
    public void connectionRequestDequeuedEvent(
            @ProbeParam("poolName") String poolName,
            @ProbeParam("appName") String appName,
            @ProbeParam("moduleName") String moduleName
            ) {

        PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of(poolName), appName, moduleName);
        if(this.poolInfo.equals(poolInfo)) {
            if(logger.isLoggable(Level.FINEST)) {
                logger.finest("Wait Queue length modified event received - " +
                    "poolName = " + poolName);
            }
            waitQueueLength.decrement();
        }
    }

    public PoolInfo getPoolInfo() {
        return poolInfo;
    }

    public void setPoolRegistry(PoolLifeCycleListenerRegistry poolRegistry) {
        this.poolRegistry = poolRegistry;
    }

    public PoolLifeCycleListenerRegistry getPoolRegistry() {
        return poolRegistry;
    }

    @ManagedAttribute(id="numpotentialconnleak")
    public CountStatistic getNumPotentialConnLeakCount() {
        return numPotentialConnLeak;
    }

    @ManagedAttribute(id="numconnfailedvalidation")
    public CountStatistic getNumConnFailedValidation() {
        return numConnFailedValidation;
    }

    @ManagedAttribute(id="numconntimedout")
    public CountStatistic getNumConnTimedOut() {
        return numConnTimedOut;
    }

    @ManagedAttribute(id="numconnused")
    public RangeStatistic getNumConnUsed() {
        return numConnUsed;
    }

    @ManagedAttribute(id="numconnfree")
    public RangeStatistic getNumConnFree() {
        return numConnFree;
    }

    @ManagedAttribute(id="connrequestwaittime")
    public RangeStatistic getConnRequestWaitTime() {
        return connRequestWaitTime;
    }

    @ManagedAttribute(id="numconndestroyed")
    public CountStatistic getNumConnDestroyed() {
        return numConnDestroyed;
    }

    @ManagedAttribute(id="numconnacquired")
    public CountStatistic getNumConnAcquired() {
        return numConnAcquired;
    }

    @ManagedAttribute(id="numconncreated")
    public CountStatistic getNumConnCreated() {
        return numConnCreated;
    }

    @ManagedAttribute(id="numconnreleased")
    public CountStatistic getNumConnReleased() {
        return numConnReleased;
    }

    @ManagedAttribute(id="numconnsuccessfullymatched")
    public CountStatistic getNumConnSuccessfullyMatched() {
        return numConnSuccessfullyMatched;
    }

    @ManagedAttribute(id="numconnnotsuccessfullymatched")
    public CountStatistic getNumConnNotSuccessfullyMatched() {
        return numConnNotSuccessfullyMatched;
    }

    @ManagedAttribute(id="averageconnwaittime")
    public CountStatistic getAverageConnWaitTime() {
       // Time taken by all connection requests divided by total number of
       // connections acquired in the sampling period.
       long count = numConnAcquired.getCount();
       long averageWaitTime = count == 0 ? 0 : totalConnRequestWaitTime.getCount() / count;

       averageConnWaitTime.setCount(averageWaitTime);
       return averageConnWaitTime;
    }

    @ManagedAttribute(id="waitqueuelength")
    public CountStatistic getWaitQueueLength() {
        return waitQueueLength;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy