com.sun.enterprise.resource.pool.monitor.ConnectionPoolEmitterImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2014 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2019] Payara Foundation and/or affiliates
package com.sun.enterprise.resource.pool.monitor;
import com.sun.appserv.connectors.internal.api.ConnectorsUtil;
import com.sun.enterprise.config.serverbeans.ResourcePool;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.resource.listener.PoolLifeCycleListener;
import com.sun.logging.LogDomains;
import org.glassfish.connectors.config.ConnectorConnectionPool;
import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;
import org.glassfish.resourcebase.resources.api.PoolInfo;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Implementation of PoolLifeCycleListener interface to listen to events related
* to jdbc monitoring. The methods invoke the probe providers internally to
* provide the monitoring related information.
*
* @author Shalini M
*/
public class ConnectionPoolEmitterImpl implements PoolLifeCycleListener {
private String poolName;
private String appName;
private String moduleName;
private PoolInfo poolInfo;
private ConnectionPoolProbeProvider poolProbeProvider;
//Map of app names and respective emitters for a pool.
private Map> appStatsMap = null;
//Map of app names for a resource handle id
private Map resourceAppAssociationMap;
private static Logger _logger = LogDomains.getLogger(ConnectionPoolEmitterImpl.class,
LogDomains.RSR_LOGGER);
private List ccPoolAppStatsProviders = null;
private ConnectorRuntime runtime;
//keep a static reference to InitialContext so as to avoid performance issues.
private volatile static InitialContext ic = null;
/**
* Constructor
* @param poolInfo connection pool on whose behalf this emitter emits pool related
* probe events
* @param provider
*/
public ConnectionPoolEmitterImpl(PoolInfo poolInfo, ConnectionPoolProbeProvider provider) {
this.poolInfo = poolInfo;
this.poolName = poolInfo.getName();
this.appName = poolInfo.getApplicationName();
this.moduleName = poolInfo.getModuleName();
this.poolProbeProvider = provider;
this.ccPoolAppStatsProviders = new ArrayList();
this.appStatsMap = new HashMap>();
this.resourceAppAssociationMap = new ConcurrentHashMap();
runtime = ConnectorRuntime.getRuntime();
if (ic == null) {
synchronized (ConnectionPoolEmitterImpl.class) {
if(ic == null) {
try{
ic = new InitialContext();
} catch (NamingException e) {
//ignore
}
}
}
}
}
/**
* Fires probe event that a stack trace is to be printed on the server.log.
* The stack trace is mainly related to connection leak tracing for the
* given jdbc connection pool.
* @param stackTrace
*/
public void toString(StringBuilder stackTrace) {
stackTrace.append("\n Monitoring Statistics for \n" + poolName);
poolProbeProvider.toString(poolName, appName, moduleName, stackTrace);
}
/**
* Fires probe event that a connection has been acquired by the application
* for the given jdbc connection pool.
*/
public void connectionAcquired(long resourceHandleId) {
ConnectionPoolAppEmitterImpl appEmitter =
detectAppBasedProviders(getAppName(resourceHandleId));
poolProbeProvider.connectionAcquiredEvent(poolName, appName, moduleName);
if(appEmitter != null) {
appEmitter.connectionAcquired();
}
}
/**
* Fires probe event related to the fact that a connection request is served
* in the time timeTakenInMillis
for the given jdbc connection
* pool.
*
* @param timeTakenInMillis time taken to serve a connection
*/
public void connectionRequestServed(long timeTakenInMillis) {
poolProbeProvider.connectionRequestServedEvent(poolName, appName, moduleName, timeTakenInMillis);
}
/**
* Fires probe event related to the fact that the given jdbc connection pool
* has got a connection timed-out event.
*/
public void connectionTimedOut() {
poolProbeProvider.connectionTimedOutEvent(poolName, appName, moduleName);
}
/**
* Fires probe event that a connection under test does not match the
* current request for the given jdbc connection pool.
*/
public void connectionNotMatched() {
poolProbeProvider.connectionNotMatchedEvent(poolName, appName, moduleName);
}
/**
* Fires probe event that a connection under test matches the current
* request for the given jdbc connection pool.
*/
public void connectionMatched() {
poolProbeProvider.connectionMatchedEvent(poolName, appName, moduleName);
}
/**
* Fires probe event that a connection is destroyed for the
* given jdbc connection pool.
*/
public void connectionDestroyed(long resourceHandleId) {
poolProbeProvider.connectionDestroyedEvent(poolName, appName, moduleName);
// Clearing the resource handle id appName mappings stored
// This is useful in cases where connection-leak-reclaim is ON where we destroy
// the connection. In this case, connection-release would not have happened.
resourceAppAssociationMap.remove(resourceHandleId);
}
/**
* Fires probe event that a connection is released for the given jdbc
* connection pool.
*/
public void connectionReleased(long resourceHandleId) {
ConnectionPoolAppEmitterImpl appEmitter =
detectAppBasedProviders(getAppName(resourceHandleId));
poolProbeProvider.connectionReleasedEvent(poolName, appName, moduleName);
if(appEmitter != null) {
appEmitter.connectionReleased();
}
// Clearing the resource handle id appName mappings stored
resourceAppAssociationMap.remove(resourceHandleId);
}
/**
* Fires probe event that a connection is created for the given jdbc
* connection pool.
*/
public void connectionCreated() {
poolProbeProvider.connectionCreatedEvent(poolName, appName, moduleName);
}
/**
* Fires probe event related to the fact that the given jdbc connection pool
* has got a connection leak event.
*
*/
public void foundPotentialConnectionLeak() {
poolProbeProvider.potentialConnLeakEvent(poolName, appName, moduleName);
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a connection validation failed event.
*
* @param count number of times the validation failed
*/
public void connectionValidationFailed(int count) {
poolProbeProvider.connectionValidationFailedEvent(poolName, appName, moduleName, count);
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a connection used event.
*/
public void connectionUsed(long resourceHandleId) {
ConnectionPoolAppEmitterImpl appEmitter =
detectAppBasedProviders(getAppName(resourceHandleId));
poolProbeProvider.connectionUsedEvent(poolName, appName, moduleName);
if (appEmitter != null) {
appEmitter.connectionUsed();
}
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a connection freed event.
*
* @param count number of connections freed to pool
*/
public void connectionsFreed(int count) {
poolProbeProvider.connectionsFreedEvent(poolName, appName, moduleName, count);
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a decrement connection used event.
*
*/
public void decrementConnectionUsed(long resourceHandleId) {
ConnectionPoolAppEmitterImpl appEmitter =
detectAppBasedProviders(getAppName(resourceHandleId));
poolProbeProvider.decrementConnectionUsedEvent(poolName, appName, moduleName);
if(appEmitter != null) {
appEmitter.decrementConnectionUsed();
}
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a decrement free connections size event.
*
*/
public void decrementNumConnFree() {
poolProbeProvider.decrementNumConnFreeEvent(poolName, appName, moduleName);
}
/**
* Fires probe event related to the fact the given jdbc connection pool has
* got a decrement free connections size event.
*
* @param beingDestroyed if the connection is destroyed due to error
* @param steadyPoolSize
*/
public void incrementNumConnFree(boolean beingDestroyed, int steadyPoolSize) {
poolProbeProvider.incrementNumConnFreeEvent(poolName, appName, moduleName, beingDestroyed, steadyPoolSize);
}
/**
* Fires probe event related to the fact the given jdbc connection pool's
* wait queue length has been incremented
*
*/
public void connectionRequestQueued() {
poolProbeProvider.connectionRequestQueuedEvent(poolName, appName, moduleName);
}
/**
* Fires probe event related to the fact the given jdbc connection pool's
* wait queue length has been decremented.
*
*/
public void connectionRequestDequeued() {
poolProbeProvider.connectionRequestDequeuedEvent(poolName, appName, moduleName);
}
private String getAppName(long resourceHandleId) {
// if monitoring is disabled, avoid sending events
// as we need to do "java:app/AppName" to get applicationName for each
// acquire/return connection call which is a performance bottleneck.
if(!runtime.isJdbcPoolMonitoringEnabled() && !runtime.isConnectorPoolMonitoringEnabled()){
return null;
}
String appName = resourceAppAssociationMap.get(resourceHandleId);
if(appName == null){
try {
if(ic == null){
synchronized(ConnectionPoolEmitterImpl.class) {
if(ic == null) {
ic = new InitialContext();
}
}
}
appName = (String) ic.lookup("java:app/AppName");
resourceAppAssociationMap.put(resourceHandleId, appName);
} catch (NamingException ex) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Unable to get application name using "
+ "java:app/AppName method");
}
}
}
return appName;
}
/**
* Detect if a Stats Provider has already been registered to the
* monitoring framework for this appName and if so, return the specific
* emitter. If not already registered, create and register the
* Stats Provider object to the monitoring framework and add to the list
* of emitters.
*
* @param appName
* @return
*/
private ConnectionPoolAppEmitterImpl detectAppBasedProviders(String appName) {
ConnectionPoolAppProbeProvider probeAppProvider = null;
ConnectionPoolAppEmitterImpl connPoolAppEmitter = null;
if (appName == null) {
//Case when appname cannot be detected. Emitter cannot exist for
//a null appName for any pool.
return null;
}
if (appStatsMap.containsKey(poolInfo)) {
//Some apps have been registered for this pool.
//Find if this appName is already registered.
//All appEmitters for this pool
Map appEmitters = appStatsMap.get(poolInfo);
//Check if the appEmitters list has an emitter for the appName.
ConnectionPoolAppEmitterImpl emitter = appEmitters.get(appName);
if(emitter != null) {
//This appName has already been registered to StatsProviderManager
return emitter;
} else {
if (!ConnectorsUtil.isApplicationScopedResource(poolInfo)) {
//register to the StatsProviderManager and add to the list.
probeAppProvider = registerConnectionPool(appName);
connPoolAppEmitter = addToList(appName, probeAppProvider,
appEmitters);
}
}
} else {
if (!ConnectorsUtil.isApplicationScopedResource(poolInfo)) {
//Does not contain any app providers associated with this poolname
//Create a map of app emitters for the appName and add them to the
//appStatsMap
probeAppProvider = registerConnectionPool(appName);
Map appEmitters =
new HashMap();
connPoolAppEmitter = addToList(appName, probeAppProvider, appEmitters);
}
}
return connPoolAppEmitter;
}
/**
* Register the jdbc/connector connection pool Stats Provider object to the
* monitoring framework under the specific application name monitoring
* sub tree.
*
* @param appName
* @return
*/
private ConnectionPoolAppProbeProvider registerConnectionPool(String appName) {
ResourcePool pool = runtime.getConnectionPoolConfig(poolInfo);
ConnectionPoolAppProbeProvider probeAppProvider =
runtime.getProbeProviderUtil().getConnPoolBootstrap().registerPool(poolInfo, appName);
if (pool instanceof ConnectorConnectionPool) {
probeAppProvider = new ConnectorConnPoolAppProbeProvider();
ConnectorConnPoolAppStatsProvider ccPoolAppStatsProvider =
new ConnectorConnPoolAppStatsProvider(poolInfo, appName);
StatsProviderManager.register(
"connector-connection-pool",
PluginPoint.SERVER,
"resources/" + ConnectorsUtil.escapeResourceNameForMonitoring(poolName) + "/" + appName,
ccPoolAppStatsProvider);
ccPoolAppStatsProviders.add(ccPoolAppStatsProvider);
}
return probeAppProvider;
}
/**
* Add to the pool emitters list. the connection pool application emitter
* for the specific poolInfo and appName.
* @param appName
* @param probeAppProvider
* @param appEmitters
* @return
*/
private ConnectionPoolAppEmitterImpl addToList(String appName,
ConnectionPoolAppProbeProvider probeAppProvider,
Map appEmitters) {
ConnectionPoolAppEmitterImpl connPoolAppEmitter = null;
if (probeAppProvider != null) {
//Add the newly created probe provider to the list.
connPoolAppEmitter = new ConnectionPoolAppEmitterImpl(poolName,
appName, probeAppProvider);
//NOTE : this appName here is different from "appName" instance variable.
appEmitters.put(appName, connPoolAppEmitter);
appStatsMap.put(poolInfo, appEmitters);
}
runtime.getProbeProviderUtil().
getConnPoolBootstrap().addToPoolEmitters(poolInfo, this);
return connPoolAppEmitter;
}
/**
* Unregister the AppStatsProviders registered for this connection pool.
*/
public void unregisterAppStatsProviders() {
runtime.getProbeProviderUtil().getConnPoolBootstrap().unRegisterPool();
Iterator ccProviders = ccPoolAppStatsProviders.iterator();
while (ccProviders.hasNext()) {
ConnectorConnPoolAppStatsProvider ccPoolAppStatsProvider =
(ConnectorConnPoolAppStatsProvider) ccProviders.next();
StatsProviderManager.unregister(ccPoolAppStatsProvider);
}
ccPoolAppStatsProviders.clear();
}
}