![JAR search and dependency download from the Maven repository](/logo.png)
net.dataforte.cassandra.pool.ConnectionPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-connection-pool Show documentation
Show all versions of cassandra-connection-pool Show documentation
Cassandra Connection Pool: a flexible, robust connection pool for Apache Cassandra
/**
* Copyright 2010 Tristan Tarrant
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dataforte.cassandra.pool;
import java.sql.SQLException;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.cassandra.thrift.AuthenticationException;
import org.apache.cassandra.thrift.AuthorizationException;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of a connection pool for Cassandra Thrift connections. Supports reaping of abandoned connections
*
* Derived from org.apache.tomcat.jdbc.pool.ConnectionPool by fhanik
*
* @author Tristan Tarrant
*
*/
public class ConnectionPool {
/**
* Prefix type for JMX registration
*/
public static final String POOL_JMX_PREFIX = "cassandra.pool";
public static final String POOL_JMX_TYPE_PREFIX = POOL_JMX_PREFIX+":type=";
/**
* Logger
*/
private static final Logger log = LoggerFactory.getLogger(ConnectionPool.class);
// ===============================================================================
// INSTANCE/QUICK ACCESS VARIABLE
// ===============================================================================
/**
* Carries the size of the pool, instead of relying on a queue
* implementation that usually iterates over to get an exact count
*/
private AtomicInteger size = new AtomicInteger(0);
/**
* All the information about the connection pool These are the properties
* the pool got instantiated with
*/
private PoolConfiguration poolProperties;
/**
* Contains all the connections that are in use TODO - this shouldn't be a
* blocking queue, simply a list to hold our objects
*/
private BlockingQueue busy;
/**
* Contains all the idle connections
*/
private BlockingQueue idle;
private Map connectionMap;
/**
* The thread that is responsible for checking abandoned and idle threads and for keeping an up-to-date list of Cassandra hosts
*/
private volatile PoolMaintenance poolMaintenance;
/**
* Pool closed flag
*/
private volatile boolean closed = false;
/**
* reference to the JMX mbean
*/
protected net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean jmxPool = null;
/**
* counter to track how many threads are waiting for a connection
*/
private AtomicInteger waitcount = new AtomicInteger(0);
/**
* the object which contains the list of active Cassandra nodes
*/
private CassandraRing cassandraRing = null;
// ===============================================================================
// PUBLIC METHODS
// ===============================================================================
/**
* Instantiate a connection pool. This will create connections if
* initialSize is larger than 0. The {@link PoolProperties} should not be
* reused for another connection pool.
*
* @param prop
* PoolProperties - all the properties for this connection pool
* @throws Exception
* @throws SQLException
*/
public ConnectionPool(PoolConfiguration prop) throws TException {
// setup quick access variables and pools
init(prop);
}
/**
* Borrows a connection from the pool. If a connection is available (in the
* idle queue) or the pool has not reached {@link PoolProperties#maxActive
* maxActive} connections a connection is returned immediately. If no
* connection is available, the pool will attempt to fetch a connection for
* {@link PoolProperties#maxWait maxWait} milliseconds.
*
* @return Connection - a java.sql.Connection/javax.sql.PooledConnection
* reflection proxy, wrapping the underlying object.
* @throws InvalidRequestException
* @throws AuthorizationException
* @throws AuthenticationException
* @throws SQLException
* - if the wait times out or a failure occurs creating a
* connection
*/
public Cassandra.Client getConnection() throws TException {
// check out a connection
PooledConnection con = borrowConnection(-1);
return con.getConnection();
}
/**
* Returns the name of this pool
*
* @return String - the name of the pool
*/
public String getName() {
return getPoolProperties().getPoolName();
}
/**
* Return the number of threads waiting for a connection
*
* @return number of threads waiting for a connection
*/
public int getWaitCount() {
return waitcount.get();
}
/**
* Returns the pool properties associated with this connection pool
*
* @return PoolProperties
*
*/
public PoolConfiguration getPoolProperties() {
return this.poolProperties;
}
/**
* Returns the total size of this pool, this includes both busy and idle
* connections
*
* @return int - number of established connections to the database
*/
public int getSize() {
return size.get();
}
/**
* Returns the number of connections that are in use
*
* @return int - number of established connections that are being used by
* the application
*/
public int getActive() {
return busy.size();
}
/**
* Returns the number of idle connections
*
* @return int - number of established connections not being used
*/
public int getIdle() {
return idle.size();
}
/**
* Returns true if {@link #close close} has been called, and the connection
* pool is unusable
*
* @return boolean
*/
public boolean isClosed() {
return this.closed;
}
public void close() {
close(false);
}
/**
* Closes the pool and all disconnects all idle connections Active
* connections will be closed upon the {@link java.sql.Connection#close
* close} method is called on the underlying connection instead of being
* returned to the pool
*
* @param force
* - true to even close the active connections
*/
public void close(boolean force) {
// are we already closed
if (this.closed)
return;
// prevent other threads from entering
this.closed = true;
// stop background thread
if (poolMaintenance != null) {
poolMaintenance.stopRunning();
}
/* release all idle connections */
BlockingQueue pool = (idle.size() > 0) ? idle : (force ? busy : idle);
while (pool.size() > 0) {
try {
// retrieve the next connection
PooledConnection con = pool.poll(1000, TimeUnit.MILLISECONDS);
// close it and retrieve the next one, if one is available
while (con != null) {
// close the connection
if (pool == idle)
release(con);
else
abandon(con);
con = pool.poll(1000, TimeUnit.MILLISECONDS);
} // while
} catch (InterruptedException ex) {
Thread.interrupted();
}
if (pool.size() == 0 && force && pool != busy)
pool = busy;
}
if (this.getPoolProperties().isJmxEnabled())
this.jmxPool = null;
} // closePool
// ===============================================================================
// PROTECTED METHODS
// ===============================================================================
/**
* Initialize the connection pool - called from the constructor
*
* @param properties
* PoolProperties - properties used to initialize the pool with
* @throws Exception
* @throws SQLException
* if initialization fails
*/
protected void init(PoolConfiguration properties) throws TException {
poolProperties = properties;
connectionMap = new HashMap();
cassandraRing = new CassandraRing(poolProperties.getConfiguredHosts());
busy = new ArrayBlockingQueue(properties.getMaxActive(), false);
if (properties.isFairQueue()) {
idle = new FairBlockingQueue();
} else {
idle = new ArrayBlockingQueue(properties.getMaxActive(), properties.isFairQueue());
}
// if the evictor thread is supposed to run, start it now
if (properties.isPoolSweeperEnabled()) {
if(log.isDebugEnabled()) {
log.debug("Starting pool maintenance thread");
}
poolMaintenance = new PoolMaintenance("[Pool-Maintenance]:" + properties.getName(), this, properties.getTimeBetweenEvictionRunsMillis());
poolMaintenance.start();
} // end if
// make sure the pool is properly configured
if (properties.getMaxActive() < properties.getInitialSize()) {
log.warn("initialSize is larger than maxActive, setting initialSize to: " + properties.getMaxActive());
properties.setInitialSize(properties.getMaxActive());
}
if (properties.getMinIdle() > properties.getMaxActive()) {
log.warn("minIdle is larger than maxActive, setting minIdle to: " + properties.getMaxActive());
properties.setMinIdle(properties.getMaxActive());
}
if (properties.getMaxIdle() > properties.getMaxActive()) {
log.warn("maxIdle is larger than maxActive, setting maxIdle to: " + properties.getMaxActive());
properties.setMaxIdle(properties.getMaxActive());
}
if (properties.getMaxIdle() < properties.getMinIdle()) {
log.warn("maxIdle is smaller than minIdle, setting maxIdle to: " + properties.getMinIdle());
properties.setMaxIdle(properties.getMinIdle());
}
// create JMX MBean
if (this.getPoolProperties().isJmxEnabled()) {
if(log.isDebugEnabled()) {
log.debug("Creating JMX MBean");
}
createMBean();
}
// initialize the pool with its initial set of members
PooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];
try {
for (int i = 0; i < initialPool.length; i++) {
initialPool[i] = this.borrowConnection(0); // don't wait, should
// be no contention
} // for
} catch (Exception x) {
if (jmxPool != null)
jmxPool.notify(net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean.NOTIFY_INIT, getStackTrace(x));
close(true);
throw new TException(x);
} finally {
// return the members as idle to the pool
for (int i = 0; i < initialPool.length; i++) {
if (initialPool[i] != null) {
try {
this.returnConnection(initialPool[i]);
} catch (Exception x) {/* NOOP */
}
} // end if
} // for
} // catch
closed = false;
if(log.isInfoEnabled()) {
log.info("ConnectionPool initialized.");
}
if(log.isTraceEnabled()) {
for(String p : PoolProperties.getPropertyNames()) {
log.trace("[" + getName() + "] ConnectionPool: "+p+"="+poolProperties.get(p));
}
}
}
// ===============================================================================
// CONNECTION POOLING IMPL LOGIC
// ===============================================================================
/**
* thread safe way to abandon a connection signals a connection to be
* abandoned. this will disconnect the connection, and log the stack trace
* if logAbanded=true
*
* @param con
* PooledConnection
*/
protected void abandon(PooledConnection con) {
if (con == null)
return;
try {
con.lock();
String trace = con.getStackTrace();
if (getPoolProperties().isLogAbandoned()) {
log.warn("[" + getName() + "] Connection has been abandoned " + con + ":" + trace);
}
if (jmxPool != null) {
jmxPool.notify(net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean.NOTIFY_ABANDON, trace);
}
// release the connection
release(con);
// we've asynchronously reduced the number of connections
// we could have threads stuck in idle.poll(timeout) that will never
// be notified
if (waitcount.get() > 0)
idle.offer(new PooledConnection(poolProperties, this));
} finally {
con.unlock();
}
}
/**
* thread safe way to abandon a connection signals a connection to be
* abandoned. this will disconnect the connection, and log the stack trace
* if logAbanded=true
*
* @param con
* PooledConnection
*/
protected void suspect(PooledConnection con) {
if (con == null)
return;
if (con.isSuspect())
return;
try {
con.lock();
String trace = con.getStackTrace();
if (getPoolProperties().isLogAbandoned()) {
log.warn("[" + getName() + "] Connection has been marked suspect, possibly abandoned " + con + "[" + (System.currentTimeMillis() - con.getTimestamp()) + " ms.]:"
+ trace);
}
if (jmxPool != null) {
jmxPool.notify(net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean.SUSPECT_ABANDONED_NOTIFICATION, trace);
}
con.setSuspect(true);
} finally {
con.unlock();
}
}
/**
* thread safe way to release a connection
*
* @param con
* PooledConnection
*/
protected void release(PooledConnection con) {
if (con == null)
return;
try {
con.lock();
if (con.release()) {
// counter only decremented once
size.addAndGet(-1);
}
} finally {
con.unlock();
}
}
/**
* Thread safe way to retrieve a connection from the pool
*
* @param wait
* - time to wait, overrides the maxWait from the properties, set
* to -1 if you wish to use maxWait, 0 if you wish no wait time.
* @return PooledConnection
* @throws InvalidRequestException
* @throws AuthorizationException
* @throws AuthenticationException
* @throws SQLException
*/
private PooledConnection borrowConnection(int wait) throws TException {
if (isClosed()) {
throw new TException("[" + getName() + "] Connection pool closed.");
} // end if
// get the current time stamp
long now = System.currentTimeMillis();
// see if there is one available immediately
PooledConnection con = idle.poll();
while (true) {
if (con != null) {
// configure the connection and return it
PooledConnection result = borrowConnection(now, con);
// null should never be returned, but was in a previous impl.
if (result != null)
return result;
}
// if we get here, see if we need to create one
// this is not 100% accurate since it doesn't use a shared
// atomic variable - a connection can become idle while we are
// creating
// a new connection
if (size.get() < getPoolProperties().getMaxActive()) {
// atomic duplicate check
if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
// if we got here, two threads passed through the first if
size.decrementAndGet();
} else {
// create a connection, we're below the limit
return createConnection(now, con);
}
} // end if
// calculate wait time for this iteration
long maxWait = wait;
// if the passed in wait time is -1, means we should use the pool
// property value
if (wait == -1) {
maxWait = (getPoolProperties().getMaxWait() <= 0) ? Long.MAX_VALUE : getPoolProperties().getMaxWait();
}
long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
waitcount.incrementAndGet();
try {
// retrieve an existing connection
con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
Thread.interrupted();// clear the flag, and bail out
TException sx = new TException("[" + getName() + "] Pool wait interrupted.");
sx.initCause(ex);
throw sx;
} finally {
waitcount.decrementAndGet();
}
if (maxWait == 0 && con == null) { // no wait, return one if we have
// one
throw new TException("[" + getName() + "] NoWait: Pool empty. Unable to fetch a connection, none available["
+ busy.size() + " in use].");
}
// we didn't get a connection, lets see if we timed out
if (con == null) {
if ((System.currentTimeMillis() - now) >= maxWait) {
if(log.isDebugEnabled()) {
int counter = 0;
for(Iterator i=busy.iterator(); i.hasNext(); ) {
PooledConnection connection = i.next();
log.debug("[" + getName() + "] Busy connection "+counter+" borrowed at "+connection.getStackTrace());
++counter;
}
}
throw new TException("[" + getName() + "] Timeout: Pool empty. Unable to fetch a connection in "
+ (maxWait / 1000) + " seconds, none available[" + busy.size() + " in use].");
} else {
// no timeout, lets try again
continue;
}
}
} // while
}
/**
* Creates a Cassandra connection and tries to connect to the database.
*
* @param now
* timestamp of when this was called
* @param con
* the previous pooled connection - argument not used
* @return a PooledConnection that has been connected
* @throws SQLException
*/
protected PooledConnection createConnection(long now, PooledConnection con) throws TException {
// no connections where available we'll create one
boolean error = false;
try {
// connect and validate the connection
con = create();
con.lock();
con.connect();
if (con.validate(PooledConnection.VALIDATE_INIT)) {
connectionMap.put(con.getConnection(), con);
// no need to lock a new one, its not contented
con.setTimestamp(now);
if (getPoolProperties().isLogAbandoned()) {
con.setStackTrace(getThreadDump());
}
if (!busy.offer(con)) {
log.debug("[" + getName() + "] Connection doesn't fit into busy array, connection will not be traceable.");
}
return con;
} else {
// validation failed, make sure we disconnect
// and clean up
error = true;
} // end if
} catch (Exception e) {
error = true;
if (log.isDebugEnabled())
log.debug("[" + getName() + "] Unable to create a new Cassandra connection.", e);
if (e instanceof TException) {
throw (TException) e;
} else {
TException ex = new TException(e.getMessage());
ex.initCause(e);
throw ex;
}
} finally {
if (error) {
release(con);
}
con.unlock();
}// catch
return null;
}
/**
* Validates and configures a previously idle connection
*
* @param now
* - timestamp
* @param con
* - the connection to validate and configure
* @return con
* @throws InvalidRequestException
* @throws AuthorizationException
* @throws AuthenticationException
* @throws SQLException
* if a validation error happens
*/
protected PooledConnection borrowConnection(long now, PooledConnection con) throws TException {
// we have a connection, lets set it up
// flag to see if we need to nullify
boolean setToNull = false;
try {
con.lock();
if (con.isReleased()) {
return null;
}
if (!con.isDiscarded() && !con.isInitialized()) {
// attempt to connect
con.connect();
}
if ((!con.isDiscarded()) && con.validate(PooledConnection.VALIDATE_BORROW)) {
// set the timestamp
con.setTimestamp(now);
if (getPoolProperties().isLogAbandoned()) {
// set the stack trace for this pool
con.setStackTrace(getThreadDump());
}
if (!busy.offer(con)) {
log.debug("[" + getName() + "] Connection doesn't fit into busy array, connection will not be traceable.");
}
return con;
}
// if we reached here, that means the connection
// is either discarded or validation failed.
// we will make one more attempt
// in order to guarantee that the thread that just acquired
// the connection shouldn't have to poll again.
try {
con.reconnect();
if (con.validate(PooledConnection.VALIDATE_INIT)) {
// set the timestamp
con.setTimestamp(now);
if (getPoolProperties().isLogAbandoned()) {
// set the stack trace for this pool
con.setStackTrace(getThreadDump());
}
if (!busy.offer(con)) {
log.debug("[" + getName() + "] Connection doesn't fit into busy array, connection will not be traceable.");
}
return con;
} else {
// validation failed.
release(con);
setToNull = true;
throw new TException("[" + getName() + "] Failed to validate a newly established connection.");
}
} catch (Exception x) {
release(con);
setToNull = true;
if (x instanceof TException) {
throw (TException) x;
} else {
TException ex = new TException(x.getMessage());
ex.initCause(x);
throw ex;
}
}
} finally {
con.unlock();
if (setToNull) {
con = null;
}
}
}
/**
* Determines if a connection should be closed upon return to the pool.
*
* @param con
* - the connection
* @param action
* - the validation action that should be performed
* @return true if the connection should be closed
*/
protected boolean shouldClose(PooledConnection con, int action) {
if (con.isDiscarded())
return true;
if (isClosed())
return true;
if (!con.validate(action))
return true;
if (getPoolProperties().getMaxAge() > 0) {
return (System.currentTimeMillis() - con.getLastConnected()) > getPoolProperties().getMaxAge();
} else {
return false;
}
}
public void release(Cassandra.Client connection) {
PooledConnection pooledConnection = connectionMap.get(connection);
this.returnConnection(pooledConnection);
}
/**
* Returns a connection to the pool If the pool is closed, the connection
* will be released If the connection is not part of the busy queue, it will
* be released. If {@link PoolProperties#testOnReturn} is set to true it
* will be validated
*
* @param con
* PooledConnection to be returned to the pool
*/
protected void returnConnection(PooledConnection con) {
if (isClosed()) {
// if the connection pool is closed
// close the connection instead of returning it
release(con);
return;
} // end if
if (con != null) {
try {
con.lock();
if (busy.remove(con)) {
if (!shouldClose(con, PooledConnection.VALIDATE_RETURN)) {
con.setStackTrace(null);
con.setTimestamp(System.currentTimeMillis());
if (((idle.size() >= poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
if (log.isDebugEnabled()) {
log.debug("[" + getName() + "] Connection [" + con + "] will be closed and not returned to the pool, idle[" + idle.size() + "]>=maxIdle["
+ poolProperties.getMaxIdle() + "] idle.offer failed.");
}
release(con);
}
} else {
if (log.isDebugEnabled()) {
log.debug("[" + getName() + "] Connection [" + con + "] will be closed and not returned to the pool.");
}
release(con);
} // end if
} else {
if (log.isDebugEnabled()) {
log.debug("[" + getName() + "] Connection [" + con + "] will be closed and not returned to the pool, busy.remove failed.");
}
release(con);
}
} finally {
con.unlock();
}
} // end if
} // checkIn
/**
* Determines if a connection should be abandoned based on
* {@link PoolProperties#abandonWhenPercentageFull} setting.
*
* @return true if the connection should be abandoned
*/
protected boolean shouldAbandon() {
if (poolProperties.getAbandonWhenPercentageFull() == 0)
return true;
float used = busy.size();
float max = poolProperties.getMaxActive();
float perc = poolProperties.getAbandonWhenPercentageFull();
return (used / max * 100f) >= perc;
}
/**
* Iterates through all the busy connections and checks for connections that
* have timed out
*/
public void checkAbandoned() {
if(log.isTraceEnabled()) {
log.trace("["+getName()+"] checking for abandoned connections");
}
try {
if (busy.size() == 0)
return;
Iterator locked = busy.iterator();
int sto = getPoolProperties().getSuspectTimeout();
while (locked.hasNext()) {
PooledConnection con = locked.next();
boolean setToNull = false;
try {
con.lock();
// the con has been returned to the pool
// ignore it
if (idle.contains(con))
continue;
long time = con.getTimestamp();
long now = System.currentTimeMillis();
if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
busy.remove(con);
abandon(con);
setToNull = true;
} else if (sto > 0 && (now - time) > (sto * 1000)) {
suspect(con);
} else {
// do nothing
} // end if
} finally {
con.unlock();
if (setToNull)
con = null;
}
} // while
} catch (ConcurrentModificationException e) {
log.debug("checkAbandoned failed.", e);
} catch (Exception e) {
log.warn("checkAbandoned failed, it will be retried.", e);
}
}
/**
* Iterates through the idle connections and resizes the idle pool based on
* parameters {@link PoolProperties#maxIdle}, {@link PoolProperties#minIdle}
* , {@link PoolProperties#minEvictableIdleTimeMillis}
*/
public void checkIdle() {
try {
if (idle.size() == 0)
return;
long now = System.currentTimeMillis();
Iterator unlocked = idle.iterator();
while ((idle.size() >= getPoolProperties().getMinIdle()) && unlocked.hasNext()) {
PooledConnection con = unlocked.next();
boolean setToNull = false;
try {
con.lock();
// the con been taken out, we can't clean it up
if (busy.contains(con))
continue;
long time = con.getTimestamp();
if ((con.getReleaseTime() > 0) && ((now - time) > con.getReleaseTime()) && (getSize() > getPoolProperties().getMinIdle())) {
if(log.isDebugEnabled()) {
log.debug("[" + getName() + "] Releasing idle connection "+con);
}
release(con);
idle.remove(con);
setToNull = true;
} else {
// do nothing
} // end if
} finally {
con.unlock();
if (setToNull)
con = null;
}
} // while
} catch (ConcurrentModificationException e) {
log.debug("[" + getName() + "] checkIdle failed.", e);
} catch (Exception e) {
log.warn("[" + getName() + "] checkIdle failed, it will be retried.", e);
}
}
/**
* Forces a validation of all idle connections if
* {@link PoolProperties#testWhileIdle} is set.
*/
public void testAllIdle() {
try {
if (idle.size() == 0)
return;
Iterator unlocked = idle.iterator();
while (unlocked.hasNext()) {
PooledConnection con = unlocked.next();
try {
con.lock();
// the con been taken out, we can't clean it up
if (busy.contains(con))
continue;
if (!con.validate(PooledConnection.VALIDATE_IDLE)) {
idle.remove(con);
release(con);
}
} finally {
con.unlock();
}
} // while
} catch (ConcurrentModificationException e) {
log.debug("[" + getName() + "] testAllIdle failed.", e);
} catch (Exception e) {
log.warn("[" + getName() + "] testAllIdle failed, it will be retried.", e);
}
}
/**
* Refreshes the ring information
*/
public void refreshRing() {
try {
if (idle.size() == 0)
return;
Iterator unlocked = idle.iterator();
while (unlocked.hasNext()) {
PooledConnection con = unlocked.next();
try {
con.lock();
// the con been taken out, we can't use it
if (busy.contains(con))
continue;
cassandraRing.refresh(con.getConnection());
// we have successfully refreshed the ring, we can quit now
log.debug("[" + getName() + "] refreshRing success, ring = "+cassandraRing);
return;
} catch (TTransportException t) {
// there was an error retrieving ring information from this connection, remove it
log.warn("[" + getName() + "] removing connection to non-responding host ");
idle.remove(con);
release(con);
} finally {
con.unlock();
}
} // while
} catch (ConcurrentModificationException e) {
log.debug("[" + getName() + "] refreshRing failed.", e);
} catch (Exception e) {
log.warn("[" + getName() + "] refreshRing failed, it will be retried.", e);
}
}
/**
* Creates a stack trace representing the existing thread's current state.
*
* @return a string object representing the current state. TODO investigate
* if we simply should store
* {@link java.lang.Thread#getStackTrace()} elements
*/
protected static String getThreadDump() {
Exception x = new Exception();
x.fillInStackTrace();
return getStackTrace(x);
}
/**
* Convert an exception into a String
*
* @param x
* - the throwable
* @return a string representing the stack trace
*/
public static String getStackTrace(Throwable x) {
if (x == null) {
return null;
} else {
java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
java.io.PrintStream writer = new java.io.PrintStream(bout);
x.printStackTrace(writer);
String result = bout.toString();
return (x.getMessage() != null && x.getMessage().length() > 0) ? x.getMessage() + ";" + result : result;
} // end if
}
/**
* Create a new pooled connection object. Not connected nor validated.
*
* @return a pooled connection object
*/
protected PooledConnection create() {
PooledConnection con = new PooledConnection(getPoolProperties(), this);
return con;
}
/**
* Hook to perform final actions on a pooled connection object once it has
* been disconnected and will be discarded
*
* @param con
*/
protected void finalize(PooledConnection con) {
}
/**
* Hook to perform final actions on a pooled connection object once it has
* been disconnected and will be discarded
*
* @param con
*/
protected void disconnectEvent(PooledConnection con, boolean finalizing) {
connectionMap.remove(con.getConnection());
}
/**
* Return the object that is potentially registered in JMX for notifications
*
* @return the object implementing the
* {@link net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean}
* interface
*/
public net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean getJmxPool() {
return jmxPool;
}
public CassandraRing getCassandraRing() {
return cassandraRing;
}
/**
* Create MBean object that can be registered.
*/
protected void createMBean() {
try {
jmxPool = new net.dataforte.cassandra.pool.jmx.ConnectionPoolMBean(this);
} catch (Exception x) {
log.warn("Unable to start JMX integration for connection pool. Instance[" + getName() + "] can't be monitored.", x);
}
}
protected class PoolMaintenance extends Thread {
protected ConnectionPool pool;
protected long sleepTime;
protected volatile boolean run = true;
PoolMaintenance(String name, ConnectionPool pool, long sleepTime) {
super(name);
this.setDaemon(true);
this.pool = pool;
this.sleepTime = sleepTime;
if (sleepTime <= 0) {
log.warn("[" + getName() + "] Database connection pool maintenance thread interval is set to 0, defaulting to 30 seconds");
this.sleepTime = 1000 * 30;
} else if (sleepTime < 1000) {
log.warn("[" + getName() + "] Database connection pool maintenance thread interval is set to lower than 1 second.");
}
}
@Override
public void run() {
while (run) {
try {
sleep(sleepTime);
} catch (InterruptedException e) {
// ignore it
Thread.interrupted();
continue;
} // catch
if (pool.isClosed()) {
if (pool.getSize() <= 0) {
run = false;
}
} else {
try {
if (pool.getPoolProperties().isRemoveAbandoned())
pool.checkAbandoned();
if (pool.getPoolProperties().getMinIdle() < pool.idle.size())
pool.checkIdle();
if (pool.getPoolProperties().isTestWhileIdle())
pool.testAllIdle();
if (pool.getPoolProperties().isAutomaticHostDiscovery()) {
pool.refreshRing();
}
} catch (Exception x) {
log.error("", x);
} // catch
} // end if
} // while
} // run
public void stopRunning() {
run = false;
interrupt();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy